basic_ios上标志的语义

Ste*_*end 28 c++ input c++-faq

我发现自己被莫名其妙反复rdstate()标志- ,good(),,bad() -以及它们是如何表达,和.eof()fail()basic_ios::operator!operator booloperator void*

有人可以让我摆脱苦难并解释这一点,所以我再也不用三思了吗?

Jam*_*lis 24

有三个标志指示错误状态:

  • badbit意味着流已经出了问题.它可能是缓冲区错误或任何向数据流提供数据的错误.如果设置了此标志,则可能您不再使用该流.

  • failbit 表示从流中提取或读取失败(或输出流的写入或插入),您需要知道该失败.

  • eofbit表示输入流已到达其末尾,没有任何内容可供阅读.请注意,只有在尝试从已到达其结尾的输入流中读取(即,在发生错误时设置,因为您尝试读取不存在的数据)时,才会设置此项.

failbit也可以由达到EOF许多操作设置.例如,如果流中只剩下空白并且您尝试读取一个int,则您将同时达到EOF并且您将无法读取int,因此将设置两个标志.

fail()功能测试badbit || failbit.

good()功能测试!(badbit || failbit || eofbit).也就是说,当没有设置任何比特时,流是好的.

您可以使用ios::clear()成员函数重置标志; 这允许您设置任何错误标志; 默认情况下(没有参数),它清除所有三个标志.

流不会过载operator bool(); operator void*()用于实现安全bool习语的有点破碎版本.如果badbitfailbit设置了此运算符重载返回null ,否则返回非null.您可以使用它来支持测试提取成功的惯用语作为循环或其他控制流语句的条件:

if (std::cin >> x) {
    // extraction succeeded
}
else {
    // extraction failed
}
Run Code Online (Sandbox Code Playgroud)

operator!()过载是的相反operator void*(); true如果设置badbit或者failbit设置则返回false.在operator!()是不是真的需要超负荷了; 它可以追溯到完全一致地支持运算符重载之前(参见sbi的问题"为什么std :: basic_ios会重载一元逻辑否定运算符?").

C++ 0x修复了导致我们必须使用安全bool习语的问题,所以在C++ 0x中,basic_ios基类模板operator bool()作为显式转换运算符重载; 此运算符与当前语义具有相同的语义operator void*().


GMa*_*ckG 17

除了詹姆斯的答案之外,重要的是要记住这些标志表示操作的结果,因此除非你执行一个,否则不会设置.

常见的错误是这样做:

#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
    }
}
Run Code Online (Sandbox Code Playgroud)

这里的问题是,我们尝试获取最后一行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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这会将支票放在正确的位置.但这非常难以驾驭; 幸运的是,对于我们来说,返回值std::getline是流,并且流有一个转换运算符,允许它在布尔上下文中进行测试,其值为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;
}
Run Code Online (Sandbox Code Playgroud)

  • +1因为突出这一点很重要.在C++中,I/O的使用过于频繁. (4认同)