COMS W4995 C++ Deep Dive for C Programmers

I/O Streams

Lecture outline

io1

  1. Code overview

    • istream& istream::operator>>(int& value)

    • ios::operator bool() const
      • same as !ios::fail()
    • I/O manipulator
      • out << setw(n) will invoke out.width(n)
  2. I/O Stream Library class hierarchy

    • std::ios, std::istream, std::cin
  3. ios_base::iostate flags and ios accessors

    • https://en.cppreference.com/w/cpp/io/ios_base/iostate

    • ios_base::iostate
      • failbit: formatting or parsing error
      • badbit: irrecoverable I/O error
      • eofbit: end-of-file (EOF) is reached
    • ios accessor functions:
      • fail(): failbit or badbit are set
      • bad(): badbit is set
      • eof(): eofbit is set
      • operator bool(): equivalent to !fail()
  4. Examples runs:

    $ echo "10 2 3 4" | ./io1
    current sum:   10	 fail()==0  bad()==0  eof()==0
    current sum:   12	 fail()==0  bad()==0  eof()==0
    current sum:   15	 fail()==0  bad()==0  eof()==0
    current sum:   19	 fail()==0  bad()==0  eof()==0
      final sum:   19	 fail()==1  bad()==0  eof()==1
    
    • Note that echo “10 2 3 4” adds ‘\n’ at the end, so 4 was read without hitting EOF.
    $ echo -n "10 2 3 4" | ./io1
    current sum:   10	 fail()==0  bad()==0  eof()==0
    current sum:   12	 fail()==0  bad()==0  eof()==0
    current sum:   15	 fail()==0  bad()==0  eof()==0
    current sum:   19	 fail()==0  bad()==0  eof()==1
      final sum:   19	 fail()==1  bad()==0  eof()==1
    
    • echo -n does not add ‘\n’ at the end, so when 4 was read, we hit EOF.
    $ echo "10 abc 3 4" | ./io1 
    current sum:   10	 fail()==0  bad()==0  eof()==0
      final sum:   10	 fail()==1  bad()==0  eof()==0
    
    • “abc” failed to parse.

io2

  1. sum_ints() rewritten to recover from error

    $ echo "10 abc 3 4" | ./io2
    current sum:   10	 fail()==0  bad()==0  eof()==0
      skipped: a
      skipped: b
      skipped: c
    current sum:   13	 fail()==0  bad()==0  eof()==0
    current sum:   17	 fail()==0  bad()==0  eof()==0
      final sum:   17	 fail()==1  bad()==0  eof()==1
    
  2. sum_ints() code walk-through

    • careful coverage of every possible case
    • ios::clear(), istream::get()
  3. C++ I/O streams vs. C standard I/O

    By default, std::cin, std::cout, and std::err are synchronized with stdin, stdout, and stderr. This means that the C++ streams are unbuffered, and each I/O operation on a C++ stream is immediately applied to the corresponding C stream’s buffer. This makes it possible to freely mix C++ and C I/O.

    You can turn off this behavior by detaching C++ streams from C streams:

    std::ios_base::sync_with_stdio(false);
    

    Possible benefits of detaching C++ streams:

    • The C++ streams are allowed to buffer their I/O independently, which may increase performance.

    But you lose the following benefits when you detach C++ streams:

    • You can no longer mix C & C++ I/O.
    • C++ streams will no longer be thread-safe.
    • '\n' may not flush standard output connected to terminal.

    Recommendation:

    • Keep the default behavior (i.e. C++ & C I/O synchronized) unless performance measurement reveals significant overhead.
    • Use '\n' instead of std::endl for terminal output.

io3

  1. Code walk-through

    • Demo (f1() version)
    • std::pair class template
    • f1()
    • operator>>()
  2. String stream

    • Revisit I/O Stream Hierarchy

    • f2():

      • getline() reads a line from an istream
      • istringstream is an istream whose character source is a string
      • f2() calls f1() not with cin, but with an istringstream
      • Error recovery is achieved without modifying f1()
  3. File stream

    • f3():
      • ifstream is an istream whose character source is a file
      • f3() calls f2() not with cin, but with an ifstream
      • Reading from a file without redirection is achieved without modifying f2()
    • Also note:
      • ifstream’s RAII paradigm – the constructor opens the file and the destructor closes it
      • failbit is set if it fails to open the file
      • ""s denotes an std::string literal