我发现自己一再感到困惑的是rdstate()
旗帜 - good()
,bad()
,eof()
,fail()
- 以及它们如何在{{1 },basic_ios::operator!
和operator bool
。
有人能让我摆脱痛苦并解释这一点,所以我再也不用三思了吗?
答案 0 :(得分:22)
有三个标志指示错误状态:
badbit
表示流已经出错了。它可能是缓冲区错误或任何向数据流提供数据的错误。如果设置了此标志,则可能您不再使用该流。
failbit
表示从流中提取或读取失败(或输出流的写入或插入),您需要知道该失败。
eofbit
表示输入流已到达终点,没有任何内容可供阅读。请注意,只有在尝试从已到达其结尾的输入流中读取(即,在发生错误时设置,因为您尝试读取不存在的数据)时,才会设置此项。
failbit
也可能由许多达到EOF的操作设置。例如,如果流中只剩下空白,并且您尝试读取int
,则两者都会达到EOF而您将无法读取int
,因此将设置两个标记。
fail()
功能测试badbit || failbit
。
good()
函数测试!(badbit || failbit || eofbit)
。也就是说,当没有设置任何位时,流是好的。
您可以使用ios::clear()
成员函数重置标志;这允许您设置任何错误标志;默认情况下(不带参数),它会清除所有三个标志。
Streams不会重载operator bool()
; operator void*()
用于实现安全bool习语的有点破解版本。如果设置了badbit
或failbit
,则此运算符重载返回null,否则返回非null。您可以使用它来支持测试提取成功的惯用语作为循环或其他控制流语句的条件:
if (std::cin >> x) {
// extraction succeeded
}
else {
// extraction failed
}
operator!()
重载与operator void*()
相反;如果设置了true
或badbit
,则返回failbit
,否则返回false
。实际上不再需要operator!()
重载;它可以追溯到完全一致地支持运算符重载之前(参见sbi的问题"Why does std::basic_ios overload the unary logical negation operator?")。
C ++ 0x修复了导致我们必须使用安全bool习惯用法的问题,所以在C ++ 0x中,basic_ios
基类模板作为显式转换运算符重载operator bool()
;此运算符与当前operator void*()
具有相同的语义。
答案 1 :(得分:16)
除了James' answer之外,重要的是要记住这些标志指示操作的结果,因此除非您执行操作,否则不会设置。
常见错误是:
#include <fstream>
#include <iostream>
#include <string>
int main()
{
std::ifstream file("main.cpp");
while (!file.eof()) // while the file isn't at eof...
{
std::string line;
std::getline(file, line); // ...read a line...
std::cout << "> " << line << std::endl; // and print it
}
}
这里的问题是,在之后我们尝试获取最后一行时才会设置eof()
,此时流会说“不,不再!”并设置它。这意味着“正确”的方式是:
#include <fstream>
#include <iostream>
#include <string>
int main()
{
std::ifstream file("main.cpp");
for (;;)
{
std::string line;
std::getline(file, line); // read a line...
if (file.eof()) // ...and check if it we were at eof
break;
std::cout << "> " << line << std::endl;
}
}
这会将支票放在正确的位置。但这非常难以驾驭;幸运的是,std::getline
的返回值是流,并且流有一个转换运算符,允许在布尔上下文中对其进行测试,其值为fail()
,其中包含{{1 }}。所以我们可以写:
eof()