2

There are different effect between vc++(debug mode) and g++, with this code

test.hh

class Test
{
public:
    int a, b, c;
    Test(int a, int b, int c) : a{ a }, b{ b }, c{ c } {      }

    Test& operator++();
    Test  operator++(int);

};
std::ostream& operator<<(std::ostream& os, const Test& t);

test.cc

std::ostream& operator<<(std::ostream& os, const Test& t)
{
    os << "{ " << t.a << ',' << t.b << ',' << t.c << " }";
    return os;
}

Test Test::operator++(int)
{
    Test temp{ *this };
    operator++();
    return temp;
}

Test& Test::operator++()
{
    ++a; ++b; ++c;
    return *this;
}

main.cc

Test t{ 1,2,3 };

std::cout << t << '\n'
          << t++ << '\n'
          << t;

in vc++ the result of execution is

{ 2,3,4 }
{ 1,2,3 }
{ 2,3,4 }

but in g++ it is

{ 1,2,3 }
{ 1,2,3 }
{ 2,3,4 }

so, Is there an compiler bug in vc++ or something what I has not learned.

Steve Wilson
  • 102
  • 4
  • To second @MikeCAT: IMHO, the impl. of your `operator++`s is OK. The unexpected results are caused by the `std::cout << t << '\n' << t++ << '\n' << t;`. Please, try again, splitting it in three separate statements: `std::cout << t << '\n'; std::cout << t++ << '\n'; std::cout << t << '\n';`. – Scheff's Cat Jul 19 '20 at 07:19
  • It's never a compiler bug. – Retired Ninja Jul 19 '20 at 07:21
  • thanks, but I wanna know is this an undefined behavior? – Steve Wilson Jul 19 '20 at 07:22
  • 1
    Depends on the age of your compilers. Before C++17, the order of evaluations of `t`, `t++`, and (the second) `t` are unspecified in `std::cout << t << '\n' << t++ << '\n' << t;`. Which, essentially, means the implementation must evaluate all three, but in any order it likes. Since C++17, the behaviour exhibited by your g++ is required. If your vc++ version predates C++17 (or its documentation doesn't claim compliance with C++17 or later) then it is correct (or, more accurately, doing something permitted). If it claims C++17/later compliance, then it is incorrect. – Peter Jul 19 '20 at 07:24
  • The answer is probably given in [Evaluation order](https://en.cppreference.com/w/cpp/language/eval_order). (Sorry, for the unspecific answer. It's a bit difficult topic.) I remember that some cases switched (with C++17) from Undefined to Implementation Defined. All I recorded: It's still nothing you really can rely on. ;-) – Scheff's Cat Jul 19 '20 at 07:25
  • The only sensible way to deal with this mess is to avoid writing this kind of code. – john Jul 19 '20 at 07:25
  • I just tested your code, with C++17 enabled VC++ produces the same output as g++, with C++14 enabled it produces the output you described. So it seems VC++ is behaving correctly. – john Jul 19 '20 at 07:30

1 Answers1

3

Unfortunately << has a psychological effect of pushing the idea of "sequencing".

While std::cout << a() << b() << c() conveys the idea of computing a(), then b() and then c() this is (was) false. You only know they will be put in the output stream in sequence, but they can be computed in any order (before C++17).

This has been fixed recently (so may be the difference you are observing depends on which C++ standard you are using), but unfortunately only for common special cases like the left-shift operator that is overloaded for stream output (IMO another sad choice of C++ for a few reasons).

6502
  • 104,192
  • 14
  • 145
  • 251