0

This is an example extracted from section 10.3.3 Input of User-defined Types from the book "The C++ Programming Language" second edition, by B. Stroustrup. The code is old but still compiles with minor changes. Example:

#include <istream>
#include <complex>

using namespace std;

istream& operator>>(istream& s, complex<double>& a)
{
    // input formats for a complex; "f" indicates a float:
    //
    //   f
    //   (f)
    //   (f, f)

    double re = 0, im = 0;
    char c = 0;

    s >> c;
    if( c == '(' ) {
        s >> re >> c;
        if( c == ',' ) s >> im >> c;
        if( c != ')' ) s.clear(ios::badbit);  // set state
    }
    else {
        s.putback(c);
        s >> re;
    }

    if( s ) a = complex<double>(re, im);
    return s;
}

Despite the scarcity of error-handling code, this will actually handle most kinds of errors. The local variable c is initilized to avoid having its value accidentally '(' after a failed operation. The final check of the stream state ensures that the value of the argument a is changed if everything went well.

I failed to understand the phrase emphasized above.

Mao
  • 1,065
  • 8
  • 12

2 Answers2

3

If s >> c fails then c is not written to.

If c was uninitialized , it remains uninitialized at the point of the test if( c == '(' ). Reading an uninitialized char causes undefined behaviour.

The author is talking about a possible way that this undefined behaviour might manifest itself.


The suggested fix of char c = 0; relies on the fact thats.putback(c); does nothing if s is not good(). This is OK, although IMHO it would be clearer to write:

char c;
s >> c;

if ( !s )
    return s;

Then anybody reading the code can immediately see that it behaves properly in case of error; instead of having to thread their way through the flow of the function and check that no other operations will do anything unexpected.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • 1
    *"s.putback(c); will be executed. This would actually put back a null byte"* - not so, as if `s >> c` failed the stream's left in an error state and the `putback` sentry check fails, becoming a no-op. (Separately, from C++11 `s >> c` sets `c` to `0` on failure, so it doesn't need to be explicitly initialised in code.) – Tony Delroy Jun 01 '15 at 01:00
  • 1
    @TonyD OK - turns out I was reading at streambuf putback, not istream putback – M.M Jun 01 '15 at 02:42
  • @M.M Why the `s.clear(ios::badbit);` in the statement `if ( c != ')' ) s.clear(ios::badbit);` above? – John Kalane May 22 '16 at 22:02
  • @JohnKalane you seem to have a new question, post it using the "Ask Question" button. You can include link to this post if you think it's relevant to your question. – M.M May 22 '16 at 22:04
2

Consider what happens if we didn't initialize c:

char c;
s >> c;
if (c == '(') { ... }

We are not checking to see if >> succeeded or failed. So if c == '(', it could be for one of two reasons:

  1. The >> succeeded and we retrieved the character '(' from the istream.
  2. The >> failed, but the random byte that happened to be in the memory for c when it was created is a '('.

If you initialize c to 0, case 2 is impossible: if the operation failed, we know that c will be 0... so we will know for sure that if we got a '(' it's because it came from the istream.

Barry
  • 286,269
  • 29
  • 621
  • 977