libc++ std::istringstream doesn't thrown excep

2019-06-18 06:05发布

问题:

After configuring a std::istringstream to throw exceptions when failbit is set I get no exceptions happening with libc++ (this is under linux with libc++ compiled with support from libcxxrt). I suppose this is a bug in libc++ or libcxxrt:

#include <iostream>
#include <sstream>

template<typename T> std::istream &getvalue(std::istream &is, T &value, const T &default_value = T())
{
    std::stringstream ss;
    std::string s;
    std::getline(is, s, ',');
    ss << s;
    if((ss >> value).fail())
        value = default_value;
    return is;
}

int main()
{
    std::string s = "123,456,789";
    std::istringstream is(s);
    unsigned n;

    try
    {
        is.exceptions(std::ios::failbit | std::ios::eofbit);

        getvalue(is, n);
        std::cout << n << std::endl;

        getvalue(is, n);
        std::cout << n << std::endl;

        // Disable EOF exception on last bit
        is.exceptions(std::ios::failbit);

        getvalue(is, n);
        std::cout << n << std::endl;

        // Force Fail reading after EOF
        getvalue(is, n);
        std::cout << n << std::endl;
    }
    catch(std::ios::failure &fail)
    {
        std::cout << "Fail" << std::endl;
    }
}

output for libstdc++:

123
456
789
Fail

libc++/libcxxrt output:

123
456
789
0

EDIT

Also tested on OS X.

Bug submitted: http://llvm.org/bugs/show_bug.cgi?id=15949

回答1:

libc++ is responding to 27.7.2.1 [istream]/p4 which describes the basic_istream parse operator>> for unsigned:

If one of these called functions throws an exception, then unless explicitly noted otherwise, the input function sets badbit in error state. If badbit is on in exceptions(), the input function rethrows the exception without completing its actions, otherwise it does not throw anything and proceeds as if the called function had returned a failure indication.

If:

is.exceptions(std::ios::failbit | std::ios::badbit);

then the desired behavior is obtained.

123
456
789
Fail

Update

chico rightly pointed out in the comments below that he expected getline(is, s, ',') to throw, not the unsigned extractor.

Looking at 21.4.8.9 [string.io]/p7 which describes this getline:

Effects: Behaves as an unformatted input function (27.7.2.3), except that it does not affect the value returned by subsequent calls to basic_istream<>::gcount(). After constructing a sentry object, if the sentry converts to true, calls str.erase() and then extracts characters from is and appends them to str as if by calling str.append(1, c) until any of the following occurs: ...

So the question becomes:

How does an unformatted input function behave?

27.7.2.3 [istream.unformatted]/p1 says:

Each unformatted input function begins execution by constructing an object of class sentry with the default argument noskipws (second) argument true. If the sentry object returns true, when converted to a value of type bool, the function endeavors to obtain the requested input. Otherwise, if the sentry constructor exits by throwing an exception or if the sentry object returns false, when converted to a value of type bool, the function returns without attempting to obtain any input. In either case the number of extracted characters is set to 0; unformatted input functions taking a character array of non-zero size as an argument shall also store a null character (using charT()) in the first location of the array. If an exception is thrown during input then ios::badbit is turned on315 in *this’s error state. (Exceptions thrown from basic_ios<>::clear() are not caught or rethrown.) If (exceptions()&badbit) != 0 then the exception is rethrown. It also counts the number of characters extracted. If no exception has been thrown it ends by storing the count in a member object and returning the value specified. In any event the sentry object is destroyed before leaving the unformatted input function.

315) This is done without causing an ios::failure to be thrown.

(emphasis added by me for readability purposes)

So this again appears to indicate that if an exception is desired from this parse operation, badbit has to be set in exceptions.