Search code examples
c++istream

What did the author mean with his comment about the input of a user-defined type?


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.


Solution

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