简体   繁体   中英

std::exchange working differently with VC++ and gcc

following code:

#include <utility>

int main()
{
  auto pos = 0;
  auto rel = pos - std::exchange(pos, pos + 1);

  return rel; // g++: 0, VC++: 1
}

If you try the code on rextester with the VC++ compiler then the result is 1, with gcc on godbolt the result is 0 (results are apparently not returned with gcc using rextester).

Question : Why are the results different?

And 2nd question : Are there any tools to check for that mistake? Any clang warnings?

My guess is that std::exchange in VC++ is called before the other operand is evaluated, whereas in gcc this is not the case. If you swap the operands pos and std::exchange the result is -1 (or 255) both VC++ and with gcc.

It is probably something about side effects - and calling std::exchange which clearly has a side-effect.

Fortunately I caught the bug with a unit test after transitioning from VC++ to gcc - and was a bit flustered at first and boiled it down to this simple (not) working example.

Binary operator - is note associated with a sequence point , meaning it is not specified in which order expressions A and B will be evaluated in A - B :

Consider two functions f() and g() . In C and C++, the + operator is not associated with a sequence point, and therefore in the expression f()+g() it is possible that either f() or g() will be executed first. [...] In C and C++, evaluating such an expression yields undefined behavior.[

Thus, your program have undefined behaviour, and any analysis of cross-compiler behaviour is futile.


In standardese, this is [intro.execution]/17 [ emphasis mine]:

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced . [ Note: In an expression that is evaluated more than once during the execution of a program, unsequenced and indeterminately sequenced evaluations of its subexpressions need not be performed consistently in different evaluations. end note ] The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. If a side effect on a memory location is unsequenced relative to either another side effect on the same memory location or a value computation using the value of any object in the same memory location , and they are not potentially concurrent, the behavior is undefined . [ Note: The next section imposes similar, but more complex restrictions on potentially concurrent computations. end note ]

[ Example:

 void g(int i) { i = 7, i++, i++; // i becomes 9 i = i++ + 1; // the value of i is incremented i = i++ + i; // the behavior is undefined i = i + 1; // the value of i is incremented }

end example ]

"Undefined behaviour" is an extremely important principle to understand. If you haven't learned about it yet, that's something you have an opportunity to address now. If behaviour is not specifically defined , then it's undefined , meaning weird things like this can and will happen.

For a given expression a - f(a) there is absolutely no requirement that the compiler execute in left to right order. The defined behaviour only states that the outcome represents both a and f(a) as evaluated independently first.

If you want your program to produce consistent, correct results then one of the challenges is to avoid undefined behaviour. How do you do this? The compiler won't tell you when you do it, it will happen silently, and it might even "work" under all the conditions you use the code.

If you want it to be truly correct you need to know a multitude of rules like this one where the behaviour is undefined and you just need to respect that. There's really no way around it. Like when dealing with iterator invalidation, free after use, and use of uninitialized variables, you have considerable responsibility to code things correctly. This is why C++ can be exceptionally challenging to code correctly.

In summary, other languages make specific guarantees about the order of execution in an expression like this. C++ does not.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM