Should extracting from a stream using the std::ws manipulator ever raise the fail bit? In the following code, a Clang-compiled (within Xcode 4.5.1) program fails the final assertion. Evidently s >> std::ws
at EOF causes a fail. Yet GCC 4.7.2 passes the assertion. Which is correct?
#include <iostream>
#include <sstream>
#include <cassert>
int main(int argc, const char * argv[])
{
{
// Read string with trailing ws.
std::istringstream s( "test " );
std::string test;
s >> std::ws;
assert( !s.fail() ); // No ws to skip, but no failure.
s >> test;
assert( test == "test" );
assert( !s.fail() );
s >> std::ws;
assert( !s.fail() ); // No prob skipping trailing ws.
}
{
// Retry with no trailing ws.
std::istringstream s( "test" );
std::string test;
s >> std::ws;
assert( !s.fail() ); // No ws to skip, but no failure.
s >> test;
assert( test == "test" );
assert( !s.fail() );
s >> std::ws;
assert( !s.fail() ); // CLANG: Skipping absent ws at eof raises failbit.
}
return 0;
}
I believe that libc++ is implementing the standard correctly.
[ I'm quoting from N3290, which is the draft C++11 standard. C++14 does not change this. ]
ws
is described in [istream.manip], which states:
Effects: Behaves as an unformatted input function (as described in 27.7.2.3, paragraph 1), except that it does not count the number of characters extracted and does not affect the value returned by subsequent calls to is.gcount(). After constructing a sentry object extracts characters as long as the next available character c is whitespace or until there are no more characters in the sequence. Whitespace characters are distinguished with the same criterion as used by sentry::sentry (27.7.2.1.3). If ws stops extracting characters because there are no more available it sets eofbit, but not fail bit.
The key phrase here for determining the correct behavior is "after constructing a sentry object".
Sentry objects are described in [istream::sentry], and the text there begins...
1 The class sentry defines a class that is responsible for doing exception safe prefix and suffix operations.
explicit sentry(basic_istream& is, bool noskipws = false);
2 Effects: If is.good() is false, calls is.setstate(failbit). Otherwise, prepares for formatted or > unformatted input. ...and so on...
That's the only sentry constructor that is available, so that's the one that libc++ uses.
So the fail bit gets set before extracts any characters, so the text at the end of the paragraph does not apply. if the stream contained " "
(i.e, a single space at the end), then calling std::ws
does not set the fail bit, just eof (which is what the OP expected to happen).
C++11, §27.7.2.4/1:
If
ws
stops extracting characters because there are no more available it setseofbit
, but notfailbit
.
So, the ws
manipulator doesn't set failbit
directly. However, as Marshall Clow points out in his answer, it doesn't have to--it is required to create a sentry object, and the sentry object is required to set the failbit if !stream.good()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With