std::stringstream 可以设置失败/坏位的方式?
Posted
技术标签:
【中文标题】std::stringstream 可以设置失败/坏位的方式?【英文标题】:Ways std::stringstream can set fail/bad bit? 【发布时间】:2011-02-03 12:13:48 【问题描述】:我用于简单字符串拆分的一段常见代码如下所示:
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
。我错过了什么?
【问题讨论】:
错误是返回对本地的引用。 很好,虽然我并不是要返回对本地的引用,但这是一个简化的示例,用于展示问题的基础 只有当您没有调用rdbuf(otherstreambuf)
时,stringstream
才会由 string
支持。
【参考方案1】:
我无法想象这个人认为可能会发生什么错误,您应该请他们解释。除了分配错误,没有什么可以出错的,正如你提到的,它们被抛出而不是被吞没。
我看到您直接缺少的唯一一件事是 ss.fail()
在 while 循环之后保证为真,因为这是正在测试的条件。 (bool(stream)
等同于 !stream.fail()
,not stream.good()
。)正如预期的那样,ss.eof()
也将是 true,表明失败是由于 EOF。
但是,对于实际发生的情况可能会有些混淆。因为 getline 使用 delim-terminated 字段而不是 delim-分隔 字段,输入"a\nb\n"
这样的数据有两个而不是三个字段,这可能令人惊讶。对于行,这是完全有意义的(并且是 POSIX 标准),但是在拆分后,您希望在 "a-b-"
中找到多少个 delim 为'-'
的字段?
顺便说一下,我会这样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;
这首先避免了 iostreams 的所有问题,避免了额外的副本(stringstream 的支持字符串;加上 substr 返回的 temp 甚至可以使用 C++0x 右值引用作为移动语义,如果支持,如所写) ,具有我期望的 split 行为(与您的不同),并且适用于任何容器。
deque<string> c;
split("a-b-", '-', back_inserter(c));
// c == "a", "b", ""
【讨论】:
关于使用s.fail()
的好处,我想s.bad()
会是更好的选择吗?或者!s.eof()
? (它应该由于EOF而结束,所以如果它不是EOF,那么它失败了对吧?)
另外,关于终止字段与分离字段的要点。我以前从来没有遇到过这个问题,但我可以看到它令人惊讶。更有理由在从结果中提取数据之前测试您获得的字段数量。
@Evan:首先确定您要检查的条件。循环后无需检查 ss 上的 fail、bad、eof 或其他任何内容,但您可能需要检查 elems,如您所说。
目前该检查是假设性的;)。有人说这会吞下一个错误,问题是,我将如何捕捉这个错误?似乎根本不需要错误检查,我只需要检查我是否得到了预期的金额。
@Evan:它应该吞下什么错误?我找不到,我倾向于说他们完全错了。 (除非他们的意思是 -terminated vs -separated,但这不是 getline 中的错误,这是一个误解。)以上是关于std::stringstream 可以设置失败/坏位的方式?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 std::stringstream 在静态内联时不能默认构造?
将 std::string 转换回使用 std::stringstream << cv::Mat 生成的 cv::Mat