代码之家  ›  专栏  ›  技术社区  ›  Steve Townsend

基本IO上的标志语义

  •  27
  • Steve Townsend  · 技术社区  · 14 年前

    我发现自己一再被 rdstate() 旗帜- good() , bad() , eof() , fail() -以及它们的表达方式 basic_ios::operator! , operator bool operator void* .

    有人能把我从痛苦中解脱出来并解释一下吗?这样我就再也不用想了。

    2 回复  |  直到 14 年前
        1
  •  22
  •   Community CDub    7 年前

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

    • badbit 意味着这条河出了点问题。它可能是一个缓冲区错误,也可能是向流提供数据的任何对象中的错误。如果设置了此标志,则很可能您将不再使用该流。

    • failbit 意味着从流中提取或读取失败(或对输出流进行写入或插入),您需要注意该失败。

    • eofbit 表示输入流已到达其结尾,没有剩余内容可供读取。请注意,只有在尝试从已到达其结尾的输入流中读取数据(即,由于尝试读取不在该输入流中的数据而发生错误时,才会设置此项)。

    这个 故障位 也可以通过许多达到EOF的操作来设置。例如,如果流中只剩下空白,并且您尝试读取 int ,您将同时达到EOF,并且您将无法阅读 int ,因此将设置这两个标志。

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

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

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

    流不会过载 operator bool() ; operator void*() 用于实现一个有点破损的safe bool习语版本。如果 巴比特 故障位 已设置,否则不为空。您可以使用它来支持将提取成功测试为循环或其他控制流语句条件的习惯用法:

    if (std::cin >> x) {
        // extraction succeeded
    }
    else {
        // extraction failed
    }
    

    这个 operator!() 过载与 运算符void*() 它回来了 true 如果 巴比特 故障位 设置和 false 否则。这个 接线员!() 不再真正需要重载;它可以追溯到完全和一致地支持运算符重载之前(参见SBI的问题 "Why does std::basic_ios overload the unary logical negation operator?" )

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

        2
  •  16
  •   Community CDub    7 年前

    除了 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() ,其中包括 Ef() . 所以我们可以写:

    #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;
    }
    
    推荐文章