basic_ios上的标志语义
我发现自己反复被rdstate()
标志困惑 – good()
, bad()
, eof()
, fail()
– 以及它们在basic_ios::operator!
中的expression方式basic_ios::operator!
, operator bool
和operator void*
。
有人能把我从痛苦中解脱出来吗,所以我再也不用再考虑了。
有三个标志表示错误状态:
-
badbit
意味着stream中出现了一些错误。 无论是向数据stream中提供数据,可能是缓冲区错误或错误。 如果这个标志被设置,那么很可能你将不再使用这个stream。 -
失败
failbit
表示从stream中提取或读取失败(或输出stream的写入或插入),并且您需要知道该失败。 -
eofbit
意味着inputstream已经到了最后,没有什么可读的。 请注意,只有在您尝试读取已达到其结尾的inputstream(即由于您尝试读取不存在的数据而发生错误时设置)时,才会设置此项。
failbit
也可以通过许多到达EOF的操作来设置。 例如,如果stream中只剩下空白,并且您尝试读取一个int
,那么您都将达到EOF,并且将无法读取该int
,因此这两个标志都将被设置。
fail()
函数testingbadbit || failbit
badbit || failbit
。
good()
函数testing!(badbit || failbit || eofbit)
。 也就是说,当没有设置任何位时,stream是好的。
你可以通过使用ios::clear()
成员函数来重置标志。 这允许你设置任何错误标志; 默认情况下(不带参数),它清除所有三个标志。
stream不会重载operator bool()
; operator void*()
用于实现安全布尔成语的有些破碎的版本。 如果设置了badbit
或failbit
则此运算符重载返回null,否则返回非null。 您可以使用这个来支持将提取成功作为循环或其他控制stream程语句的条件进行testing的习惯用法:
if (std::cin >> x) { // extraction succeeded } else { // extraction failed }
operator!()
重载与operator void*()
相反。 如果badbit
或failbit
被设置,则返回true
否则返回false
。 operator!()
重载不再是真正需要的了; 它可以追溯到操作符重载完全一致的支持(请参阅sbi的问题“为什么std :: basic_ios重载一元逻辑否定运算符?” )。
C ++ 0x修复了导致我们不得不使用安全布尔成语的问题,因此在C ++ 0x中, basic_ios
基类模板确实将operator bool()
重载为显式转换运算符; 该运算符与当前operator void*()
具有相同的语义。
除了詹姆斯的回答之外 ,记住这些标志表示操作的结果是很重要的,所以除非你执行一个操作,否则不会被设置。
一个常见的错误是这样做的:
#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()
将不会被设置,直到我们试图获得最后一行,在这一点上,stream将会说“不,不再有! 并设置它。 这意味着“正确”的方式是:
#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
的返回值是stream,stream有一个转换运算符,它允许在布尔上下文中进行testing,其值为fail()
,其中包括eof()
。 所以我们可以写:
#include <fstream> #include <iostream> #include <string> int main() { std::ifstream file("main.cpp"); std::string line; while (std::getline(file, line)) // get line, test if it was eof std::cout << "> " << line << std::endl; }