5

How can I detect whether the istream extraction failed like this?

string s("x");
stringstream ss(s);
int i;
ss >> std::ios::hex >> i;

EDIT -- Though the question title covers this, I forgot to mention in the body: I really want to detect whether the failure is due to bad formatting, i.e. parsing, or due to any other IO-related issue, in order to provide proper feedback (an malformed_exception("x") or whatever).

xtofl
  • 40,723
  • 12
  • 105
  • 192

4 Answers4

9
if(! (ss >> std::ios::hex >> i) ) 
{
  std::cerr << "stream extraction failed!" << std::endl;
}

It's just that easy.

ETA: Here's an example of how this test interacts with the end of a stream.

int i;
std::stringstream sstr("1 2 3 4");
while(sstr >> i)
{
    std::cout << i << std::endl;
    if(sstr.eof())
    {
        std::cout << "eof" << std::endl;
    }
}

will print
1
2
3
4
eof

If you were to check sstr.eof() or sstr.good() in the while loop condition, 4 would not be printed.

01d55
  • 1,872
  • 13
  • 22
  • Thanks; indeed, it catches bad parsing. However, it also catches any other `bad()` situation (cfr http://www.cplusplus.com/reference/iostream/ios/operator_voidpt/). I believe testing for the `sstr.rdstate() & ios::failbit` would be more accurate. – xtofl Dec 13 '11 at 21:59
  • If you were to check `sstr.eof()` in the while loop condition, 4 would be printed. – ctn Mar 30 '16 at 16:17
  • @ctn `while(sstr>> i && !(sstr.eof()))` would fail to print 4, which I believe is what I had in mind when I wrote what I did back in 2011. On the other hand, either `while(!(sstr.eof()) && sstr >> i)` or `while(!(sstr.eof())) { sstr>>i` will print 4. Looking at it now, that last formulation is a more intuitive reading. – 01d55 Mar 31 '16 at 01:12
  • Yes, the last formulation is what I had in mind too. It also seems more useful when checking errors: `while (!sstr.eof()) { if (!(sstr >> i)) { error("not a number"); } }` – ctn Mar 31 '16 at 11:25
4

Failure to extract the value will set the stream's "fail" bit, which can be detected by if (ss.fail()), or just if (!ss). Equivalently, you can test the result of the >> operation, since that returns a reference to the stream.

These will also detect other errors, which set the "bad" bit; you can distinguish these with ss.bad().

If you want to continue reading from the stream, you'll need to clear the state flags (ss.clear()).

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • `ss.bad()` and `!ss` test two different things. First tests for underlying media failure (badbit), while the other tests for that and additionally for formatted input failure (badbit | failbit). – wilx Dec 13 '11 at 12:15
  • @wilx: Yes, I got "bad" and "fail" mixed up. Fixed now. – Mike Seymour Dec 13 '11 at 12:17
0

Errors during extraction are signaled by the internal state flags. You can check them by the good() member function. See also here: http://www.cplusplus.com/reference/iostream/stringstream

Or just using the if()-construction as suggested above. This works due to the bool cast operator of stream classes

xtofl
  • 40,723
  • 12
  • 105
  • 192
Zappotek
  • 344
  • 2
  • 5
  • Thanks for the reference. Did you realize that your answer gets above the 'suggestion above' if it were accepted? – xtofl Dec 13 '11 at 22:08
0

First off: thanks for the useful answers. However, after some investigation (cfr. cppreference) and verification, it seems that the one way to check for parse-failure only is by checking for the ios::failbit flag, as in

const bool parsing_failed = (ss >> ios::hex >> i).rdstate() & ios::failbit ;

While both the suggested istream::operator! and istream::operator bool mingle failbit and badbit (cfr here and there on cplusplusreference).

xtofl
  • 40,723
  • 12
  • 105
  • 192
  • It certainly looks complicated - I need to look this up again in order to understand it :(. What kind of wrong do _you_ mean? – xtofl Dec 10 '18 at 09:24