2010-04-01 37 views
9

Một mảnh thông thường mã tôi sử dụng cho tách chuỗi đơn giản trông như thế này:Cách std :: stringstream có thể đặt lỗi/bit xấu?

inline std::vector<std::string> split(const std::string &s, char delim) { 
    std::vector<std::string> elems; 
    std::stringstream ss(s); 
    std::string item; 
    while(std::getline(ss, item, delim)) { 
     elems.push_back(item); 
    } 
    return elems; 
} 

Có người nói rằng điều này sẽ âm thầm "nuốt" lỗi xảy ra trong std::getline. Và tất nhiên tôi đồng ý như vậy. Nhưng nó đã xảy ra với tôi, những gì có thể có thể đi sai ở đây trong thực tế mà tôi sẽ cần phải lo lắng về. về cơ bản tất cả nắm như thế này:

inline std::vector<std::string> split(const std::string &s, char delim) { 
    std::vector<std::string> elems; 
    std::stringstream ss(s); 
    std::string item; 
    while(std::getline(ss, item, delim)) { 
     elems.push_back(item); 
    } 

    if(/* what error can I catch here? */) { 
     // *** How did we get here!? *** 
    } 

    return elems; 
} 

Một stringstream được hỗ trợ bởi một string, vì vậy chúng tôi không cần phải lo lắng về bất kỳ vấn đề liên quan đến việc đọc từ một tập tin. Không có chuyển đổi loại nào xảy ra ở đây vì getline chỉ cần đọc cho đến khi nó thấy đường phân cách hoặc EOF. Vì vậy, chúng tôi không thể nhận được bất kỳ lỗi nào giống như boost::lexical_cast phải lo lắng.

Tôi chỉ đơn giản là không thể nghĩ ra điều gì đó ngoài việc không phân bổ đủ bộ nhớ có thể sai, nhưng điều đó sẽ chỉ ném một số std::bad_alloc trước khi số std::getline thậm chí diễn ra. Tôi đang thiếu gì?

+1

Điều gì sai là trả lại tham chiếu đến địa phương. – UncleBens

+1

Tốt bắt, mặc dù tôi không có nghĩa là trả lại một tham chiếu đến một địa phương, đây là một ví dụ cắt giảm để chứng minh những điều cơ bản của câu hỏi –

+1

Một 'stringstream' được hỗ trợ bởi một' chuỗi' chỉ nếu bạn chưa gọi 'rdbuf (otherstreambuf)'. –

Trả lời

6

Tôi không thể tưởng tượng những lỗi mà người này nghĩ có thể xảy ra và bạn nên yêu cầu họ giải thích. Không có gì có thể đi sai trừ lỗi phân bổ, như bạn đã đề cập, được ném và không nuốt phải.

Điều duy nhất tôi thấy rằng bạn đang mất tích trực tiếp là ss.fail() được đảm bảo là đúng sau vòng lặp while, vì đó là điều kiện đang được kiểm tra. (bool(stream) tương đương với !stream.fail(), khôngstream.good().) Như dự kiến, ss.eof() cũng sẽ đúng, cho biết lỗi là do EOF.

Tuy nhiên, có thể có một số nhầm lẫn về những gì đang thực sự xảy ra. Bởi vì getline sử dụng dấu phân cách - chấm dứt lĩnh vực chứ không phải là dấu phân cách - tách lĩnh vực, dữ liệu đầu vào như "a\nb\n" có hai thay vì ba lĩnh vực, và điều này có thể là đáng ngạc nhiên. Đối với các dòng này có ý nghĩa hoàn chỉnh (và là tiêu chuẩn POSIX), nhưng có bao nhiêu trường, với delim của '-', bạn sẽ tìm thấy trong "a-b-" sau khi tách?


Ngẫu nhiên, dưới đây là cách tôi muốn writesplit:

template<class OutIter> 
OutIter split(std::string const& s, char delim, OutIter dest) { 
    std::string::size_type begin = 0, end; 
    while ((end = s.find(delim, begin)) != s.npos) { 
    *dest++ = s.substr(begin, end - begin); 
    begin = end + 1; 
    } 
    *dest++ = s.substr(begin); 
    return dest; 
} 

Điều này tránh tất cả các vấn đề với iostreams ở nơi đầu tiên, tránh thêm bản sao (string sự ủng hộ của stringstream; cộng với nhiệt độ trở lại bởi substr thậm chí có thể sử dụng tham chiếu rvalue C++ 0x cho ngữ nghĩa di chuyển nếu được hỗ trợ, như được viết), có hành vi mà tôi mong đợi từ việc tách (khác với của bạn), và làm việc với bất kỳ vùng chứa nào.

deque<string> c; 
split("a-b-", '-', back_inserter(c)); 
// c == {"a", "b", ""} 
+0

điểm tốt về việc sử dụng 's.fail()', tôi cho rằng 's.bad()' sẽ là một lựa chọn tốt hơn? hoặc có lẽ '! s.eof()'? (nó sẽ kết thúc do EOF, vì vậy nếu nó không phải là EOF, sau đó nó thất bại phải không?) –

+0

Ngoài ra, điểm tốt về chấm dứt vs các lĩnh vực riêng biệt. Tôi đã không bao giờ có một vấn đề với điều đó trước đây, nhưng tôi có thể thấy nó là đáng ngạc nhiên. Tất cả các lý do khác để kiểm tra số lĩnh vực bạn có trước khi trích xuất dữ liệu của bạn từ kết quả. –

+0

@Evan: Trước tiên hãy xác định điều kiện bạn đang cố gắng kiểm tra. Không cần phải kiểm tra thất bại, xấu, eOF, hoặc bất cứ điều gì khác trên * ss * sau vòng lặp, nhưng bạn có thể muốn kiểm tra * elems *, như bạn đã nói. –

Các vấn đề liên quan