Reputation: 674
I'm in the process of writing my own output streaming library and I'm trying to mimic std::ostream behaviors where it doesn't conflict with the new behaviors I'm trying to achieve. Currently I'm trying to mimic this interface inherited from ios:
std::ostream::exceptions(ios::iostate state)
According to cplusplus.com:
"this method sets a new exception mask for the stream and clears the stream's error state flags (as if member clear() was called)."
It wasn't clear to me whether this meant all flags would be cleared or only the ones being set in the exceptions mask, so I wrote a test program but got quite unexpected results. Here's the program:
#include <sstream>
#include <iostream>
using namespace std;
int main(int argc, char** argv)
{
ostringstream oss;
try
{
cout << " badbit = " << ios::badbit << "\n";
cout << " eofbit = " << ios::eofbit << "\n";
cout << " failbit = " << ios::failbit << "\n\n";
cout << " oss.rdstate() = " << oss.rdstate() << "\n";
cout << " oss.exceptions() = " << oss.exceptions() << "\n\n";
cout << "executing: oss.setstate(ios::badbit | ios::failbit);" << "\n";
oss.setstate(ios::badbit | ios::failbit);
cout << " oss.rdstate() = " << oss.rdstate() << "\n";
cout << " oss.exceptions() = " << oss.exceptions() << "\n\n";
cout << "executing: oss.exceptions(ios::failbit);" << "\n";
oss.exceptions(ios::failbit);
cout << " oss.rdstate() = " << oss.rdstate() << "\n";
cout << " oss.exceptions() = " << oss.exceptions() << "\n";
}
catch(const exception& x)
{
cout << endl;
cout << "**** EXCEPTION THROWN ****" << "\n";
cout << argv[0] << ": " << x.what() << endl;
cout << " oss.rdstate() = " << oss.rdstate() << "\n";
cout << " oss.exceptions() = " << oss.exceptions() << "\n";
return 1;
}
catch(...)
{
cerr << argv[0] << ": unknown exception." << endl;
return 1;
}
return 0;
}
And here's the output:
matt@dworkin:~/dev/ostream/libs/ostream$ g++ --version
g++ (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
matt@dworkin:~/dev/ostream/libs/ostream$ g++ --std=c++17 foo.cpp
matt@dworkin:~/dev/ostream/libs/ostream$ ./a.out
badbit = 1
eofbit = 2
failbit = 4
oss.rdstate() = 0
oss.exceptions() = 0
executing: oss.setstate(ios::badbit | ios::failbit);
oss.rdstate() = 5
oss.exceptions() = 0
executing: oss.exceptions(ios::failbit);
**** EXCEPTION THROWN ****
./a.out: basic_ios::clear: iostream error
oss.rdstate() = 5
oss.exceptions() = 4
So based on the cplusplus.com docs, I wasn't expecting an exception to be thrown at all. And as can be seen from the output generated from within the exception handler, no state flags were ever cleared. So is this a compiler bug, a documentation bug, or am I missing something?
As an aside, I prefer the behavior exhibited over the behavior documented. Seems sorta strange to me that a request to throw on errors would have the side-affect of erasing existing errors. I actually first implemented it the same way g++ apparently does (assuming this was the way it would surely work), and only then read the docs for this method.
Upvotes: 0
Views: 294
Reputation: 33952
cplusplus.com is wrong. They are correct that clear
is called by exceptions
, but it is not called to clear the state and the state is not cleared.
In spite of the name, clear
is used in the back end by iostreams, including setstate
itself, to do the grunt work for a great deal of setting, not just clearing, of the stream's state. As such, it is the logical place to house the raising of exceptions and other flag-related behaviours.
In exceptions
it appears clear
is being used primarily test for existing flags to raise an exception should any of the desired flags already be set. To actually clear the flags after the exception, a call to clear
is still required to remove the error flags.
Upvotes: 1