我用于简单字符串拆分的一段常见代码如下所示:
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;
}
stringstream
由string
支持,因此我们不必担心与从文件读取相关的任何问题。这里没有进行类型转换,因为 getline
只是读取直到它看到行分隔符或 EOF
。所以我们不会得到像 boost::lexical_cast
这样的东西必须担心的任何错误。
除了未能分配足够的内存可能会出错,我实在想不出还有什么,但这只会在 std::getline 之前抛出一个
甚至发生。我错过了什么?std::bad_alloc
最佳答案
我无法想象这个人认为可能会出现什么错误,你应该请他们解释。除了您提到的分配错误外,没有什么会出错,分配错误是抛出而不是吞噬。
我看到您直接遗漏的唯一一件事是 ss.fail()
在 while 循环之后保证为真,因为这是被测试的条件。 (bool(stream)
等同于 !stream.fail()
,不是 stream.good()
。 ) 正如预期的那样,ss.eof()
也将为真,表明失败是由于 EOF。
但是,对于实际发生的事情可能会有一些混淆。因为 getline 使用 delim-terminated 字段而不是 delim-separated 字段,输入"a\nb\n"
等数据有两个字段而不是三个字段,这可能会令人惊讶。对于行,这是完全有意义的(并且是 POSIX 标准),但是您希望在 中找到多少字段,delim 为
split 后?'-'
a-b-”
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;
}
这首先避免了 iostream 的所有问题,避免了额外的拷贝(stringstream 的支持字符串;加上 substr 返回的 temp,如果支持的话,甚至可以使用 C++0x 右值引用来移动语义,如所写) ,具有我期望的 split 行为(与您的行为不同),并且适用于任何容器。
deque<string> c;
split("a-b-", '-', back_inserter(c));
// c == {"a", "b", ""}
关于c++ - std::stringstream 可以设置失败/坏位的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2562906/