std::stringstream 的 seekg 在 while 循环后不起作用

std::stringstream's seekg does not work after while loop

我有这个 std::stringstream 对象,我必须(只)读取它的内容两次。为此,我想我可以使用它的 seekg 成员函数来重复阅读。但我无法让它发挥作用。这是一个重现我遇到的问题的 MWE(改编自示例 in the docs)。

#include <iostream>
#include <string>
#include <sstream>

int main()
{
    const char *str = "Hello, world";
    std::stringstream ss(str);

    std::string word1 = "asdf";
    std::string word2 = "qwer";
    std::string word3 = "zxcv";
    std::string word4 = "yuio";

    ss >> word1;
    ss.seekg(0); // rewind
    ss >> word2;
    while (ss >> word3) { }
    ss.seekg(0); // rewind
    ss >> word4;

    std::cout << "word1 = " << word1 << '\n'
              << "word2 = " << word2 << '\n'
              << "word3 = " << word3 << '\n'
              << "word4 = " << word4 << '\n';
}

我希望内容是:

word1 = Hello,
word2 = Hello,
word3 = world
word4 = Hello,

因为 while 循环后的调用 ss.seekg(0) 应该将 ss 放在其内容的开头。为什么我没有得到预期的输出,而是这个?

word1 = Hello,
word2 = Hello,
word3 = world
word4 = yuio

这意味着 word4 永远不会更新,因此语句 ss >> word4 无效。但是在这种情况下,ss.seekg(0) 也没有任何作用。

while 循环是否导致 ss 对象“倒带”失败?也许 ss 试图读取太多,现在处于错误状态(我不知道)。

我该如何解决这个问题?也就是说,我怎样才能使语句 ss >> word4 读作 Hello,?

我在 C++17 上使用 g++ (Ubuntu 11.1.0-1ubuntu1~20.04) 11.1.0

seekg 首先构造并检查哨兵对象(由 cppstreams 使用它来表示任何流故障),如果该哨兵对象表示任何故障,那么函数只是 returns 而不做任何事情。

while 循环后,ssfailbiteofbit 将被设置。对 seekg 的调用将如前所述(不会执行任何操作)。

要使 seekg 生效,您必须在 while 循环之后调用 seekg 本身之前调用 ss.clear() 来清除失败位。然后,哨兵对象不会表示任何失败,seekg 将按预期运行。

相关链接:

https://en.cppreference.com/w/cpp/io/basic_istream/operator_gtgt2

https://en.cppreference.com/w/cpp/io/basic_istream/seekg