Is this a bug in C++? (Book <<C++ primer>> might be wrong?)

Viewed 106
//Wrong Code
#include<iostream>
#include<iterator>
using namespace std;
int main(){
    istream_iterator<string> in_iter(cin),eof;
    ostream_iterator<string> out_iter(cout," ");
    while(in_iter!=eof)
        *out_iter++ = *in_iter++;
}

Input:(Run the code above in interactive mode through "visual c++"、"cpp.sh"、"onlinegdb" and whatever tool you like...)

aa bb cc 6 dd ee

Output:

aa bb cc 6 dd

Actually the correct code should be:

#include<iostream>
#include<iterator>
using namespace std;
int main(){
    istream_iterator<string> in_iter(cin),eof;
    ostream_iterator<string> out_iter(cout," ");
    while(in_iter!=eof){
        *out_iter = *in_iter;
         out_iter++;
         in_iter++;
    }
}

Input:

aa bb cc 6 dd ee

Output:

aa bb cc 6 dd ee

Description: Very easy code. Just for printing some characters and output will be the same. However, in the book of "C++ Primer", as the picture shown below, it gives us a wrong code. Is it a bug of C++ or just the mistake of "C++ Primer"? Picture of "C++ Primer"

1 Answers

Let's take apart this command and see what's happening:

*out_iter++ = *in_iter++;

It can be also written in the following way, according to operator precedence:

// read next value, but return unmodified iterator (with the previous value)
// the first value is read when the iterator is constructed!
auto x = in_iter++; 

// get value that was previously read
const auto res = *x; 

// print this value
*out_iter++ = res;

So basically this prints a value only after reading the next one. For an input of "a b c" the following happens:

  1. constructor istream_iterator<string> in_iter(cin) reads "a"
  2. auto x = in_iter++; reads "b", but returns an iterator containing "a"
  3. const auto res = *x; results in "a", which then is printed.
  4. auto x = in_iter++; reads "c", but returns an iterator containing "b"
  5. const auto res = *x; results in "b", which then is printed.
  6. auto x = in_iter++; tries to read something, but the streambuffer is empty, so it waits for further input.

So far only "a b" was printed and "c" is "stuck" in in_iter.

If the stream would contain an [eof] (e.g. if you terminate the stream somehow), step 6 would be different and step 7 (and 8) would happen:

  1. auto x = in_iter++; reads [eof], becomes the eof-iterator and returns an iterator containing "c"
  2. const auto res = *x; results in "c", which then is printed.
  3. loop terminates

So this code is not wrong, it just does not do what one would intuitively expect.


Your code on the other hand does the following:

// extract first value that was read by the constructor and "prepare" to print
*out_iter = *in_iter; 

// read next value
out_iter++;

// print value
in_iter++;

This works as expected, because it does prints the old value before it reads a new one.

Related