basic_ios 上标志的语义
我发现自己反复对 rdstate() 标志感到困惑 - good()
、bad()
、eof()
、fail()
- 以及它们如何在 basic_ios::operator!
、operator bool
和 operator void*
中表达代码>.
有人能让我摆脱痛苦并解释一下这一点,这样我就不必再三思而行了吗?
I find myself repeatedly baffled by the rdstate()
flags - good()
, bad()
, eof()
, fail()
- and how they are expressed in basic_ios::operator!
, operator bool
and operator void*
.
Could somebody put me out of my misery and explain this so I never have to think twice again?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
有三个标志指示错误状态:
badbit
表示流出现严重错误。这可能是缓冲区错误或向流提供数据的任何错误。如果设置了此标志,您可能不会再使用该流。failbit
表示从流中提取或读取失败(或输出流的写入或插入)失败,您需要了解该失败。eofbit
表示输入流已到达末尾,没有任何内容可供读取。请注意,仅在您尝试从已到达末尾的输入流中读取数据后才设置此值(即,由于您尝试读取不存在的数据而发生错误时设置此值)。failbit
也可以由许多到达 EOF 的操作来设置。例如,如果流中只剩下空格,并且您尝试读取int
,则双方都会到达 EOF 并且无法读取int
,因此两个标志都将被设置。fail()
函数测试badbit ||失败位
。good()
函数测试!(badbit ||failbit || eofbit)
。也就是说,当没有设置任何位时,流是好的。您可以使用 ios::clear() 成员函数重置标志;这允许您设置任何错误标志;默认情况下(不带参数),它会清除所有三个标志。
流不会重载
operator bool()
;operator void*()
用于实现安全 bool 习惯用法的一个有些损坏的版本。如果设置了badbit
或failbit
,则此运算符重载返回 null,否则返回非 null。您可以使用它来支持测试提取是否成功的习惯用法,作为循环或其他控制流语句的条件:operator!()
重载与operator void 相反*()
;如果设置了badbit
或failbit
,则返回true
,否则返回false
。实际上不再需要operator!()
重载;它可以追溯到完全一致地支持运算符重载之前(请参阅 sbi 的问题 “为什么 std::basic_ios 重载一元逻辑否定运算符?”)。C++0x 修复了导致我们必须使用安全 bool 习惯用法的问题,因此在 C++0x 中,
basic_ios
基类模板会重载operator bool()
作为显式转换运算符;该运算符与当前运算符 void*()
具有相同的语义。There are three flags that indicate error state:
badbit
means something has gone very wrong with the stream. It might be a buffer error or an error in whatever is feeding data to the stream. If this flag is set, it's likely that you aren't going to be using the stream anymore.failbit
means that an extraction or a read from the stream failed (or a write or insertion for output streams) and you need to be aware of that failure.eofbit
means the input stream has reached its end and there is nothing left to read. Note that this is set only after you attempt to read from an input stream that has reached its end (that is, it is set when an error occurs because you try to read data that isn't there).The
failbit
may also be set by many operations that reach EOF. For example, if there is only whitespace left remaining in the stream and you try to read anint
, you will both reach EOF and you will fail to read theint
, so both flags will be set.The
fail()
function testsbadbit || failbit
.The
good()
function tests!(badbit || failbit || eofbit)
. That is, a stream is good when none of the bits are set.You can reset the flags by using the
ios::clear()
member function; this allows you to set any of the error flags; by default (with no argument), it clears all three flags.Streams do not overload
operator bool()
;operator void*()
is used to implement a somewhat broken version of the safe bool idiom. This operator overload returns null ifbadbit
orfailbit
is set, and non-null otherwise. You can use this to support the idiom of testing the success of an extraction as the condition of a loop or other control flow statement:The
operator!()
overload is the opposite of theoperator void*()
; it returnstrue
if thebadbit
orfailbit
is set andfalse
otherwise. Theoperator!()
overload is not really needed anymore; it dates back to before operator overloads were supported completely and consistently (see sbi's question "Why does std::basic_ios overload the unary logical negation operator?").C++0x fixes the problem that causes us to have to use the safe bool idiom, so in C++0x the
basic_ios
base class template does overloadoperator bool()
as an explicit conversion operator; this operator has the same semantics as the currentoperator void*()
.除了 James 的回答之外,重要的是要记住这些标志表示操作的结果,因此除非您执行操作,否则不会被设置。
这样做的一个常见错误是:
这里的问题是
eof()
不会被设置,直到之后我们尝试获取最后一行,此时流会说“不,不再了!”并设置它。这意味着“正确”的方法是:将支票放在正确的位置。但这是非常不守规矩的;幸运的是,
std::getline
的返回值是流,并且该流有一个转换运算符,允许在布尔上下文中对其进行测试,其值为fail( )
,其中包括eof()
。所以我们可以这样写:In addition to James' answer, it's important to remember that these flags indicate results of operations, so won't be set unless you perform one.
A common error is to do this:
The problem here is that
eof()
won't be set until after we try to get the last line, at which point the stream will say "nope, no more!" and set it. This means the "correct" way is:This places the check in the correct location. This is very unruly though; luckily for us, the return value for
std::getline
is the stream, and the stream has a conversion operator that allows it to be tested in a boolean context, with the value offail()
, which includeseof()
. So we can just write: