std::istream::sentry 与 std::istream 一起使用

Use of std::istream::sentry with std::istream

考虑以下简单程序,它将输入拆分为空白并每行打印一个非空白标记:

#include <iostream>
int main(int argc, char* argv[])
{
        while (std::cin)
        {
                std::string s;
                std::cin >> s;
                std::cout << "-" << s << "-\n";
        }
        return 0;
}

这工作正常 - 除了因为输入流仅指示 EOF 我们试图从它读取时,当它到达输入流的末尾时(^D) 它读入并发出一个空字符串:

[begin]
< a b c
> -a-
> -b-
> -c-
< (^D)
> --
[end]

我们可以通过使输出行以 !s.empty() 为条件来处理这个问题。

不过还有另一种选择。我们可以替换行:

while (std::cin)

与:

while (std::istream::sentry(std::cin))

哨兵对象(通常由 operator>> 内部使用)具有消耗空白和 然后 检查 EOF 或其他流状态的效果:

[begin]
< a b c
> -a-
> -b-
> -c-
< (^D)
[end]

我的问题有三个:

std::istream::sentry用于内部输入函数。正确解决问题的方法是 始终 检查流是否良好,即读取成功 after reading:

for (std::string s; std::cin >> s; ) {
    std::cout << '-' << s << "-\n";
}

流无法提前知道读取操作是否会成功。做完了就知道了

使用 sentry 的方法通常适用于字符串,但对于需要任何格式的类型可能会失败。例如,如果您需要读取 int,跳过带有 sentry 的 space 并不表示是否可以读取 int。即使使用 std::strings,该方法也可能失败:流可以在第一次访问时提供字符,但在第二次访问时失败。第一次访问是确定该字符不是来自 sentry 构造函数的 space,随后从字符串中读取失败。