3

I trying to run a simple c++ program, but I'm not sure why different compilers provide different output

#include <iostream>

struct A
{
    A() { std::cout << "Object A created" << std::endl; }

    friend std::ostream& operator<<(std::ostream& os, const A& a)
    {
        os << a.str << "\n";
        return os;
    }

    static bool printMe()
    {
        std::cout << "static bool printMe() of object A" << std::endl;
        return true;
    }
    std::string str{"This is object A"};
};


int main()
{
    std::cout << A() << (A::printMe() ? "TRUE" : "FALSE") << std::endl;
}

OUTPUT1: Some compilers provide the following output:

Object A created
This is object A
static bool printMe() of object A
TRUE

For example: https://www.programiz.com/cpp-programming/online-compiler/

OUTPUT2: Other compilers provide the other output:

static bool printMe() of object A
Object A created
This is object A
TRUE

For example: http://cpp.sh/

I cannot understand why some compilers execute the static function before creating object A I would expect the order will be kept and Object A will be created bfore static function will be called as in OUTPUT2.

Mat
  • 202,337
  • 40
  • 393
  • 406
ol202020
  • 95
  • 6
  • 1
    c++ makes no guarantees of this. – Daniel A. White Dec 31 '21 at 20:36
  • Specify -std=c++17 if you want defined order. See [Order of evaluation](https://en.cppreference.com/w/cpp/language/eval_order) *`cout << i << i++; // undefined behavior until C++17`* – 273K Dec 31 '21 at 20:38
  • If I cannot switch to c++17, Is there any compiler flag to force this order? – ol202020 Dec 31 '21 at 20:40
  • 1
    @273K The order of the presented code is *unspecified*, not *undefined*. In your example the UB comes from modifying `i` in an *unspecified* order. – Quimby Dec 31 '21 at 20:42
  • 1
    Basically, the compiler guarantees the order in which the insertions (overloaded bitshift operator) will happen, but the only guarantees about when it computes the values to be inserted is that each happens at some point in time before the insertion happens. There are actually 3 legal orderings -- `cout << f() << g()` can be the same as `auto e1 = f(); auto e2 = g(); cout << e1; cout << e2;` or `auto e1 = f(); cout << e1(); auto e2 = g(); cout << e2;` or the one you saw `auto e2 = g(); auto e1 = f(); cout << e1; cout << e2;` – Ben Voigt Dec 31 '21 at 21:00

1 Answers1

6

Before C++17, the order of evaluating sub-expressions in an expression is mostly unspecified, the compiler is free to order them as it sees fit. In C++17, the order is more strictly defined, in particular:

In a shift operator expression E1<<E2 and E1>>E2, every value computation and side-effect of E1 is sequenced before every value computation and side effect of E2 [cppreference]

So if you add -std=c++17, you should only see OUTPUT1.

?'s order has always been defined, so that's safe.

Quimby
  • 17,735
  • 4
  • 35
  • 55
  • 1
    Also, note that the order of evaluation for function arguments is still unspecified. The reason for that is that it allows the compiler to better optimize the code in some cases. – digito_evo Dec 31 '21 at 20:43
  • 2
    Are you sure I should see OUTPUT2 with c++17. I have run with this compiler set to C++17 and got OUTPUT1 https://www.onlinegdb.com/online_c++_compiler – ol202020 Dec 31 '21 at 20:48
  • 1
    @ol202020 Oops, sorry, it should be OUTPUT1, the evaluation order is basically left-to-right. – Quimby Dec 31 '21 at 20:53
  • Thanks, but in previous releases of g++ (11/14) is there any compiler flag or workaround we can do to force that order, or we should avoid evaluating on the same line code? – ol202020 Dec 31 '21 at 20:59
  • 1
    @ol202020: The compiler doesn't care about lines, it cares about full-expressions (separated by semicolons). – Ben Voigt Dec 31 '21 at 21:01
  • Thanks, Ben, I'm aware of this, just wondering if there is any compiler flag to force it evaluating from left to right, but I guess not. – ol202020 Dec 31 '21 at 21:06
  • @ol202020 Unfortunately I do not know of any, at least for gcc. – Quimby Dec 31 '21 at 22:33
  • @ol202020 - It is still considered good style to **not** make computations or modify the values *while* they are being printed. Even if the compiler *might* understand the code, it is still hard to read for us humans. So, compute the values first, then display the results. – BoP Dec 31 '21 at 23:33