C++ - 重置 stringstream 是否不会重置获取位置或清除标志?

C++ - Does resetting stringstream not reset the get position or clear flags?

我在循环中从字符串流中提取值,每次循环执行时都在循环顶部重置字符串流。但是,stringstream 的 >> 运算符每次都会在第二次迭代时失败。这个代码的精简版本重现了我遇到的问题:

istringstream word;
string in;
int number;

while(cin >> in) {

   word.str(in);

   //Uncommenting either one of the following lines seems to solve the issue:
   //word.clear();
   //word.seekg(0);

   word >> number;

   if(word.fail()) {
       cerr << "Failed to read int" << endl;
       return 1;
   }

   cout << in << ' ' << number << endl;
}

就目前而言,它总是在第二次循环迭代时失败。但是,取消注释两行注释代码中的任何一行都可以解决问题。我不明白的是,既然我已经用 word.str(in) 重置了字符串流,为什么它仍然失败?为什么重置获取位置可以解决问题?

我是否遗漏了有关字符串流工作原理的信息?它是否在最后一次有效读取而不是由于 EOF 而失败的读取上设置 eofbit 标志?如果是这样,为什么 seekg(0) 似乎清除了该标志,而重置 stringstream 却没有?

正如@Someprogrammerdude 建议的那样:只需将 istringstream 移动到 while 循环中(您可以将其更改为 for 循环以将 in 保留在循环中嗯):

for (string in; cin >> in;)
{
    istringstream word(in);
    int number;
    if (!(word >> number))
    {
        cerr << "Failed to read int" << endl;
        return 1;
    }
    cout << in << ' ' << number << endl;
}

这样每个循环都会重新创建。

当你这样做的时候,把 number 也移进去(当然,除非你在循环外使用它)。

如果你看一下流的状态,这应该会更清楚一些。

int main()
{
    std::vector<std::string> words = { "10", "55", "65" };
    std::istringstream word;
    for (const auto &in : words)
    {
        word.str(in);
        std::cout << "stream state:"
            << (word.rdstate() & std::ios::badbit ? " bad" : "")
            << (word.rdstate() & std::ios::failbit ? " fail" : "")
            << (word.rdstate() & std::ios::eofbit ? " eof" : "")
            << std::endl;
        int number;
        word >> number;

        if (word.fail()) {
            std::cerr << "Failed to read int" << std::endl;
            return 1;
        }

        std::cout << in << ' ' << number << std::endl;
        std::cout << "stream state:"
            << (word.rdstate() & std::ios::badbit ? " bad" : "")
            << (word.rdstate() & std::ios::failbit ? " fail" : "")
            << (word.rdstate() & std::ios::eofbit ? " eof" : "")
            << std::endl;
    }
}

这将导致:

stream state:
10 10
stream state: eof
stream state: eof
Failed to read int

所以最初设置了 none 个标志,但是读取数字到达流的末尾,设置 eofbitstd::istringstream::str is defined as if to call rdbuf()->str(new_str)。这与清除标志无关。

调用 clear() 当然会清除 eofbit,但在 C++11 或更新的 中调用 seekg 也会清除。 “ 在做任何事情之前,seekg 清除 eofbit。 (C++11 起)".

请注意,如果您说“10 20”,它只会丢弃“20”,而不会检测到错误。

stream state:
10 20 10
stream state:
stream state:
55 55
stream state: eof
stream state: eof
Failed to read int

所以您可能真的想检查那个 eof 标志,看看您是否阅读了整个流。

正如其他人所指出的,当然每个循环构造一个新的流对象也意味着不用担心以前的 flags/states。