Issue
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.
Solution
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()
andg()
. In C and C++, the+
operator is not associated with a sequence point, and therefore in the expressionf()+g()
it is possible that eitherf()
org()
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 ]
Answered By - dfrib Answer Checked By - Marie Seifert (WPSolving Admin)