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::string
s,该方法也可能失败:流可以在第一次访问时提供字符,但在第二次访问时失败。第一次访问是确定该字符不是来自 sentry
构造函数的 space,随后从字符串中读取失败。
考虑以下简单程序,它将输入拆分为空白并每行打印一个非空白标记:
#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::string
s,该方法也可能失败:流可以在第一次访问时提供字符,但在第二次访问时失败。第一次访问是确定该字符不是来自 sentry
构造函数的 space,随后从字符串中读取失败。