Today I came across some code that exhibits different behavior on
clang++ (3.7-git), g++ (4.9.2) and Visual Studio 2013. After some reduction
I came up with this snippet which highlights the issue:
#include <iostream>
using namespace std;
int len_ = -1;
char *buffer(int size_)
{
cout << "len_: " << len_ << endl;
return new char[size_];
}
int main(int argc, char *argv[])
{
int len = 10;
buffer(len+1)[len_ = len] = '\0';
cout << "len_: " << len_ << endl;
}
g++ (4.9.2) gives this output:
len_: -1
len_: 10
So g++ evaluates the argument to buffer, then buffer(..) itself and after that it evaluates the index argument to the array operator. Intuitively this makes sense to me.
clang (3.7-git) and Visual Studio 2013 both give:
len_: 10
len_: 10
I suppose clang and VS2013 evaluates everything possible before it decends into buffer(..). This makes less intuitive sense to me.
I guess the gist of my question is whether or not this is a clear case of undefined behavior.
Edit: Thanks for clearing this up, and unspecified behavior is the term I should have used.
Best Answer
This is unspecified behavior,
len_ = len
is indeterminately sequenced with respect to the execution of the body ofbuffer()
, which means that one will be executed before the other but it is not specified which order but there is an ordering so evaluations can not overlap therefore no undefined behavior. This meansgcc
,clang
andVisual Studio
are all correct. On other hand unsequenced evaluations allow for overlapping evaluations which can lead to undefined behavior as noted below.From the draft C++11 standard section
1.9
[intro.execution]:and indeterminately sequenced is covered a little before this and says:
which is different than unsequenced evaluations:
which can lead to undefined behavior (emphasis mine):
Pre C++11
Pre C++11 the order of evaluation of sub-expressions is also unspecified but it uses sequence points as opposed to ordering. In this case, there is a sequence point at function entry and function exit which ensures there is no undefined behavior. From section
1.9
:Nailing down order of evaluation
The different choices made by each compiler may seem unintuitive depending on your perspective and expectations. The subject of nailing down order of evaluation is the subject of EWG issue 158: N4228 Refining Expression Evaluation Order for Idiomatic C++, which is being considered for C++17 but seems controversial based on the reactions to a poll on the subject. The paper covers a much more complicated case from "The C++ Programming Language" 4th edition. Which shows even those with deep experience in C++ can get tripped up.