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

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

本文关键字:std istream sentinel 一起      更新时间:2023-10-16

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

#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在输入函数中使用。解决问题的正确方法是总是检查流是否正常,即在 reading:

之后读取成功。
for (std::string s; std::cin >> s; ) {
    std::cout << '-' << s << "-n";
}

流不能提前知道读操作是否成功。完成后,它就知道了。

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