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
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
.