2010-04-01 34 views
9

代碼的一個公共的一塊,我使用簡單的字符串分割看起來是這樣的:方式std :: stringstream可以設置失敗/壞點?

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; 
} 

有人提到這會悄悄出現在std::getline「燕子」的錯誤。當然,我同意這種情況。但它發生在我身上,在這裏可能會出錯在實踐中,我將需要擔心。基本上這一切歸結爲:

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; 
} 

一個stringstreamstring的支持,所以我們不必擔心任何與從文件中讀取相關的問題。這裏沒有類型轉換,因爲getline只是讀取直到看到行分隔符或EOF。所以我們不能得到像boost::lexical_cast這樣的錯誤。

我根本無法想到除了沒有分配足夠的內存以外可能會出錯,但在std::getline甚至發生之前,這隻會拋出一個std::bad_alloc。我錯過了什麼?

+1

什麼是錯誤的是返回一個本地引用。 – UncleBens 2010-04-01 19:34:29

+1

好,但我並不是想要返回一個本地引用,這是一個簡化的例子來演示這個問題的基礎 – 2010-04-01 19:37:56

+1

只有當你還沒有調用stringstream時,'stringstream'才支持'rdbuf(otherstreambuf)'。 – 2011-06-26 04:45:23

回答

6

我無法想象這個人認爲會發生什麼錯誤,你應該讓他們解釋。除了分配錯誤之外,沒有什麼可以出錯的,正如你所提到的那樣,它們被拋出並且不被吞下。

我看到你直接丟失的唯一東西是ss.fail()在while循環後保證是真的,因爲那是被測試的條件。 (bool(stream)相當於!stream.fail(),而不是stream.good())。正如預期的那樣,ss.eof()也是如此,表明失敗是由於EOF造成的。

但是,實際發生的事情可能存在一些混淆。因爲函數getline使用DELIM - 終止而字段不是DELIM - 分離領域,如"a\nb\n"輸入數據具有兩個而不是三個字段,並且這可能是令人驚訝的。對於這些行是完全有意義的(並且是POSIX標準),但是有多少個字段,delim'-',你會期望在分裂後在"a-b-"中找到?


順便說一句,這裏就是我倒是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; 
} 

這就避免了所有與擺在首位輸入輸出流的問題,避免了額外的副本(該字符串流的後盾串;加上臨時返回通過substr甚至可以使用C++ 0x右值引用移動語義(如果支持,如書面所示),具有我期望從split(與您不同)的行爲,並且可以與任何容器一起使用。

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

關於使用's.fail()'的好處,我想's.bad()'會是更好的選擇嗎?或者'!s.eof()'? (它應該由於EOF而結束,所以如果它不是EOF,那麼它失敗了吧?) – 2010-04-01 21:57:05

+0

另外,關於終止vs分隔字段的好處。我以前從來沒有遇到過這個問題,但我可以看到它令人驚訝。在從結果中提取數據之前測試所得字段的數量的更多理由。 – 2010-04-01 22:07:07

+0

@Evan:首先確定您要檢查的狀況。正如你所說的,在循環之後不需要檢查* ss *上的失敗,不好,eof或其他任何東西,但是你可能想檢查* elems *。 – 2010-04-01 22:12:52