2010-04-01 23 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