Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What value should `std::stringstream::fail()` return after reading then writing? (gcc vs clang)

Consider the following code snippet:

#include <iostream>
#include <sstream>

int main()
{
    std::stringstream ss;
    ss << "12345";
    unsigned short s;
    ss >> s;
    ss << "foo";

    std::cout << std::boolalpha
              << "\nss.eof()  = " << ss.eof()
              << "\nss.good() = " << ss.good()
              << "\nss.bad()  = " << ss.bad()
              << "\nss.fail() = " << ss.fail()
              << "\nss.str()  = " << ss.str();
}

clang++ trunk prints the following result:

ss.eof()  = true
ss.good() = false
ss.bad()  = false
ss.fail() = false
ss.str()  = 12345

on wandbox


g++ trunk prints the following result:

ss.eof()  = true
ss.good() = false
ss.bad()  = false
ss.fail() = true
ss.str()  = 12345

on wandbox


As you can see, the value of ss.fail() is different between the two compilers. What does the Standard say regarding the behavior of std::stringstream in this case? Is it implementation-defined to set failbit/badbit when writing to a stream that has already been consumed?

like image 966
Vittorio Romeo Avatar asked Nov 22 '17 15:11

Vittorio Romeo


1 Answers

Gcc is correct. std::stringstream inherits from std::basic_ostream, and according to the behavior of operator<<(std::basic_ostream) (which is invoked from ss << "foo";),

Effects: Behaves like a formatted inserter (as described in [ostream.formatted.reqmts]) of out.

And from §30.7.5.2.1/1 Common requirements [ostream.formatted.reqmts]:

(emphasis mine)

Each formatted output function begins execution by constructing an object of class sentry. If this object returns true when converted to a value of type bool, the function endeavors to generate the requested output. If the generation fails, then the formatted output function does setstate(ios_­base​::​failbit), which might throw an exception.

And §30.7.5.1.3 Class basic_­ostream​::​sentry [ostream::sentry]:

If os.good() is nonzero, prepares for formatted or unformatted output. If os.tie() is not a null pointer, calls os.tie()->flush().

If, after any preparation is completed, os.good() is true, ok_­ == true otherwise, ok_­ == false. During preparation, the constructor may call setstate(failbit) (which may throw ios_­base​::​​failure ([iostate.flags]))

And §30.5.5.4 basic_­ios flags functions [iostate.flags]:

iostate rdstate() const;
Returns: The error state of the stream buffer.

bool good() const;
Returns: rdstate() == 0

bool eof() const;
Returns: true if eofbit is set in rdstate().

eofbit has been set in this case, then std::basic_ios::good returns nonzero and causes writing failed (as the result showed), then failbit should be set.

like image 110
songyuanyao Avatar answered Oct 28 '22 09:10

songyuanyao