关于使用flagbit设置内部错误标志的说明

Gau*_*rav 8 c++ io

在C++入门中我找到了这段代码:

 if (cin.fail())
 { // bad input
      cerr<< "bad data, try again"; // warn the user
      cin.clear(istream::failbit); // reset the stream
      continue; // get next input
 }
Run Code Online (Sandbox Code Playgroud)

我很困惑,为什么istream::failbit用于设置错误状态标志,我的意思是,因为错误已经发生(因此流程现在在if块然后必须设置failbit,他们为什么用它来设置错误标志那又一次.我在理解这个问题上哪里错了?

编辑:该书说"我们打印一个警告并清除failbit状态",但IMO clear(istream :: failbit)正在使用failbit中包含的值设置的当前状态.那么为什么本书将流的状态设置为failbit,因为它将阻止cin运行,因为它将处于错误状态.++++通过流的状态,实际上谈论的是什么,是eofbit,badbit,goodbit,failbit还是它们的组合?我怎么知道这些单独位的价值呢?

Swi*_*Pie 1

std::basic_ios::清除

\n\n
void clear( std::ios_base::iostate state = std::ios_base::goodbit ); \n
Run Code Online (Sandbox Code Playgroud)\n\n

通过为流错误状态标志分配 的值来设置它们state。默认情况下,分配std::ios_base::goodbit具有清除所有错误状态标志的效果。

\n\n

如果rdbuf() 是空指针(即没有关联的流缓冲区),则state | badbit分配。可能会抛出异常。

\n\n

本质上,在这种情况下,设置位意味着将位设置为清除状态。

\n\n

如果您不带参数调用clear,它会通过设置“goodbit”将所有位设置为清除状态,这与其他状态是互斥的。如果您仅标记某个位,则只会设置该位,并清除其他位(​​以及好位)。无论如何,如上所述,如果在调用此方法期间流的输入缓冲区无效,则clear()也会设置badbit为 true,因此方法good()operator bool将返回false并且fail()仍然会返回true

\n\n

也就是说,为什么需要清除这些位但保持错误状态取决于进一步的代码,通常是能够检测到发生的错误,但能够从流中请求更多数据(要求正确的输入?)

\n\n
#include <iostream>\n#include <limits> \n#include <string> \nint main() {\n    using std::cout;\n    using std::cin;\n\n    int a;\n    do\n    {\n        cout << " Please enter an integer number:";\n        cin.clear();\n        cin >> a;\n        if(cin.fail())\n        {\n            cout << "Error occured while parsing input.\\n";\n            cin.clear(std::istream::failbit);\n        }\n\n\n        // do something\n\n        if(cin.fail())\n        {\n            std::string str;\n                    //now clear everything,  to unlock the input.\n            cin.clear(); \n            cin >> str;\n            cout << "Wrong input was: " << str << "\\n";\n            cin.ignore(std::numeric_limits<std::streamsize>::max(), \'\\n\');\n                    // setting fail bit again, so   loop will go on\n            cin.clear(std::istream::failbit);\n        }\n\n    } while(cin.fail());\n    cout << "Thank you!";\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果没有调用::clear(std::istream::failbit)::ignore循环将永远工作,因为标志和缓冲区的状态将迫使尝试一遍又一遍地解析相同的缓冲区内容。实际上,您可以尝试重新解析它,例如读取字符串并打印它。直接调用就可以了clear(),但是我们需要创建自己的标志来让我们做出正确的反应。

\n\n

流的“状态”是类型的私有字段std::ios_base::iostate,其值等于 it eofbitbadbitfailbit常量的二进制组合。 goodbitConstant 等于 0,表示无错误状态。提供对该字段的读写操作的两个访问器:

\n\n
void setstate( iostate state );\niostate rdstate() const;\n
Run Code Online (Sandbox Code Playgroud)\n\n

注意,setstate(state)得到 的效果clear(rdstate() | state),这意味着如果clear可以设置 iostate 的精确值,setstate 只能将新的位设置为 true,而不能清除已经设置的位。

\n\n
int main()\n{\n  std::ostringstream stream;\n\n  if (stream.rdstate() == std::ios_base::goodbit) {\n    std::cout << "stream state is goodbit\\n";\n  }\n\n  stream.setstate(std::ios_base::eofbit);\n\n  // check state is exactly eofbit (no failbit and no badbit)\n  if (stream.rdstate() == std::ios_base::eofbit) {\n    std::cout << "stream state is eofbit\\n";\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

对于每个位,都有访问器:fail()bad()eof()good().\n本质上,fail()如果 则返回 true (rdstate()|std::ios_base::failbit) != 0,依此类推(请参阅 30.5.5.4 basic_ios 标志函数、ISO/IEC 14882:2017、编程\n语言 \xe2\x80\x94 C++)

\n\n
    \n
  • operator bool被定义并返回good()
  • \n
  • operator!被定义并返回!good()
  • \n
\n\n

线路

\n\n
if (stream.rdstate() == std::ios_base::goodbit)\n
Run Code Online (Sandbox Code Playgroud)\n\n

可以替换为

\n\n
if (stream)\n
Run Code Online (Sandbox Code Playgroud)\n\n

因为后者会导致上下文转换为bool.

\n\n

iostate与\ 位相关的效果(根据 ISO C++):

\n\n
\n
    \n
  • badbit表示输入或输出序列的完整性丢失(例如文件中不可恢复的读取错误);
  • \n
  • eofbit表示输入操作到达输入序列的末尾;
  • \n
  • failbit表示输入操作未能读取预期的字符,或者输出操作未能生成\n 所需的字符。
  • \n
\n
\n