Unexpected order of evaluation (compiler bug?)
There is a sequence point between evaluating arguments and calling a function. There is no sequence point between evaluating different arguments.
Let's look at the outermost function call:
operator<<(operator<<(operator<<(std::cout, n++), n), ++n)
The arguments are
operator<<(operator<<(std::cout, n++), n)
and
++n
It is unspecified which of these is evaluated first. It's also allowed that the first argument is partially evaluated when the second argument is evaluated.
From the standard, section [intro.execution]
(wording from draft 3225):
If A is not sequenced before
B and B is not sequenced before A, then A and B are unsequenced. [ Note: The execution of unsequenced
evaluations can overlap. — end note ]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 scalar
object is unsequenced relative to either another side effect on the same scalar object or a value computation
using the value of the same scalar object, the behavior is undefined.
Because you have multiple operations with side effects on the same scalar object which are unsequenced with respect to each other, you're in that realm of undefined behavior, and even 999
would be a permissible output.
Unexpected flow of control (compiler-bug?) using errno as argument for exception in C++ (g++)
What this basically means is that errno as an argument to a C++ exception is pretty much useless due to the call to __cxa_allocate_exception preceding the call to __errno_location (which is the macro content of errno), where the former calls std::malloc and does not save errno state (at least as far as I understood the sources of __cxa_allocate_exception in eh_alloc.cc of libstdc++).
This is not true. As far as I have checked the source code, the only "thing" inside __cxa_allocate_exception
that can change errno
is malloc()
. Two cases may occur:
malloc()
succeeds, thenerrno
is unchanged;malloc()
fails, thenstd::terminate()
is called and youroserror()
is never constructed.
Therefore, since calling _cxa_allocate_exception
before calling your constructor does not functionally change your program, I believe g++ has the right to do so.
Order of evaluation of arguments using std::cout
The evaluation order of elements in an expression is unspecified (except some very particular cases, such as the &&
and ||
operators and the ternary operator, which introduce sequence points); so, it's not guaranteed that test
will be evaluated before or after foo(test)
(which modifies it).
If your code relies on a particular order of evaluation the simplest method to obtain it is to split your expression in several separated statements.
Undefined behavior and sequence points
C++98 and C++03
This answer is for the older versions of the C++ standard. The C++11 and C++14 versions of the standard do not formally contain 'sequence points'; operations are 'sequenced before' or 'unsequenced' or 'indeterminately sequenced' instead. The net effect is essentially the same, but the terminology is different.
Disclaimer : Okay. This answer is a bit long. So have patience while reading it. If you already know these things, reading them again won't make you crazy.
Pre-requisites : An elementary knowledge of C++ Standard
What are Sequence Points?
The Standard says
At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations
shall be complete and no side effects of subsequent evaluations shall have taken place. (§1.9/7)
Side effects? What are side effects?
Evaluation of an expression produces something and if in addition there is a change in the state of the execution environment it is said that the expression (its evaluation) has some side effect(s).
For example:
int x = y++; //where y is also an int
In addition to the initialization operation the value of y
gets changed due to the side effect of ++
operator.
So far so good. Moving on to sequence points. An alternation definition of seq-points given by the comp.lang.c author Steve Summit
:
Sequence point is a point in time at which the dust has settled and all side effects which have been seen so far are guaranteed to be complete.
What are the common sequence points listed in the C++ Standard?
Those are:
at the end of the evaluation of full expression (
§1.9/16
) (A full-expression is an expression that is not a subexpression of another expression.)1Example :
int a = 5; // ; is a sequence point here
in the evaluation of each of the following expressions after the evaluation of the first expression (
§1.9/18
) 2a && b (§5.14)
a || b (§5.15)
a ? b : c (§5.16)
a , b (§5.18)
(here a , b is a comma operator; infunc(a,a++)
,
is not a comma operator, it's merely a separator between the argumentsa
anda++
. Thus the behaviour is undefined in that case (ifa
is considered to be a primitive type))
at a function call (whether or not the function is inline), after the evaluation of all function arguments (if any) which
takes place before execution of any expressions or statements in the function body (§1.9/17
).
1 : Note : the evaluation of a full-expression can include the evaluation of subexpressions that are not lexically
part of the full-expression. For example, subexpressions involved in evaluating default argument expressions (8.3.6) are considered to be created in the expression that calls the function, not the expression that defines the default argument
2 : The operators indicated are the built-in operators, as described in clause 5. When one of these operators is overloaded (clause 13) in a valid context, thus designating a user-defined operator function, the expression designates a function invocation and the operands form an argument list, without an implied sequence point between them.
What is Undefined Behaviour?
The Standard defines Undefined Behaviour in Section §1.3.12
as
behavior, such as might arise upon use of an erroneous program construct or erroneous data, for which this International Standard imposes no requirements 3.
Undefined behavior may also be expected when this
International Standard omits the description of any explicit definition of behavior.
3 : permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or with-
out the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).
In short, undefined behaviour means anything can happen from daemons flying out of your nose to your girlfriend getting pregnant.
What is the relation between Undefined Behaviour and Sequence Points?
Before I get into that you must know the difference(s) between Undefined Behaviour, Unspecified Behaviour and Implementation Defined Behaviour.
You must also know that the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified
.
For example:
int x = 5, y = 6;
int z = x++ + y++; //it is unspecified whether x++ or y++ will be evaluated first.
Another example here.
Now the Standard in §5/4
says
- Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression.
What does it mean?
Informally it means that between two sequence points a variable must not be modified more than once.
In an expression statement, the next sequence point
is usually at the terminating semicolon, and the previous sequence point
is at the end of the previous statement. An expression may also contain intermediate sequence points
.
From the above sentence the following expressions invoke Undefined Behaviour:
i++ * ++i; // UB, i is modified more than once btw two SPs
i = ++i; // UB, same as above
++i = 2; // UB, same as above
i = ++i + 1; // UB, same as above
++++++i; // UB, parsed as (++(++(++i)))
i = (i, ++i, ++i); // UB, there's no SP between `++i` (right most) and assignment to `i` (`i` is modified more than once btw two SPs)
But the following expressions are fine:
i = (i, ++i, 1) + 1; // well defined (AFAIK)
i = (++i, i++, i); // well defined
int j = i;
j = (++i, i++, j*i); // well defined
- Furthermore, the prior value shall be accessed only to determine the value to be stored.
What does it mean? It means if an object is written to within a full expression, any and all accesses to it within the same expression must be directly involved in the computation of the value to be written.
For example in i = i + 1
all the access of i
(in L.H.S and in R.H.S) are directly involved in computation of the value to be written. So it is fine.
This rule effectively constrains legal expressions to those in which the accesses demonstrably precede the modification.
Example 1:
std::printf("%d %d", i,++i); // invokes Undefined Behaviour because of Rule no 2
Example 2:
a[i] = i++ // or a[++i] = i or a[i++] = ++i etc
is disallowed because one of the accesses of i
(the one in a[i]
) has nothing to do with the value which ends up being stored in i (which happens over in i++
), and so there's no good way to define--either for our understanding or the compiler's--whether the access should take place before or after the incremented value is stored. So the behaviour is undefined.
Example 3 :
int x = i + i++ ;// Similar to above
Follow up answer for C++11 here.
C++ std::cout and operator, priority
The order of the evaluation is unspecified.
Take a look to this answer, a great explanation on this type of result
What is run first inside a cout statement? (C++17)
Since C++17 the functions are guaranteed to be called left-to-right, i.e. findCurrent()
is called first, then findLowest()
and so on.
C++17 Standard references: [expr.shift]/4 (referring to the expression E1 << E2
):
The expression
E1
is sequenced before the expressionE2
.
[over.match.oper]/2: (describing overloaded operators)
the operands are sequenced in the order prescribed for the built-in operator.
[intro.execution]/15:
An expression
X
is said to be sequenced before an expressionY
if every
value computation and every side effect associated with the expressionX
is sequenced before every value computation and every side effect associated with the expressionY
.
Link to cppreference summary
Prior to C++17 the order of function calls was unspecified, meaning that they may be called in any order (and this order does not need to be the same on repeated invocations).
What's the order of evaluation with this compound assignment in Java?
Assignment is right associative. This means the statement is interpreted as:
odd = (odd.next = even.next);
This is different to many operators. For instance subtraction, 1 - 2 - 3
is (1 - 2) - 3
not 1 - (2 - 3)
.
How does cout's operator work with regard to operator precedence?
Undefined behaviour. Could do anything.
See this answer for a good explanation.
Related Topics
How to Compare Multiple Strings Inside an If Statement
Sort Array by First Item in Subarray C++
Q_Object Throwing 'Undefined Reference to Vtable' Error
When Are Static and Global Variables Initialized
What Does Template <Unsigned Int N> Mean
How to Read/Write Arbitrary Bits in C/C++
How to Initialize Std::Array<T, N> Elegantly If T Is Not Default Constructible
Is Right Shift Undefined Behavior If the Count Is Larger Than the Width of the Type
How to Catch the Null Pointer Exception
How Does the Omp Ordered Clause Work
What Is Indeterminate Behavior in C++ ? How Is It Different from Undefined Behavior
Disambiguate Class-Member in Multiple Inheritance
Is There a Difference Between Universal References and Forwarding References
Declaring the Array Size with a Non-Constant Variable
How to Write a Type Trait 'Is_Container' or 'Is_Vector'