For example:
int foo(int i) { return i; }
int main()
{
int i = 0;
i = i++; // Undefined
i = foo(i++); // ?
return 0;
}
What would the current ISO C++ standard specify for this case?
EDIT:
Here's where I get confused:
Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.
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, and they are not potentially concurrent (1.10), the behavior is
undefined.
In all cases, the assignment is sequenced after the value
computation of the right and left operands, and before the value computation of the assignment expression
Every evaluation in the calling function (including other function calls) that is not otherwise specifically
sequenced before or after the execution of the body of the called function is indeterminately sequenced with
respect to the execution of the called function.
So it seems you could have a value computation on the left side of the assignment (just i), and a side effect on the right side (the modification of i from i++) which aren't sequenced with respect to each other.
EDIT2:
For anyone who finds themselves here, there is a really great explanation about sequencing that I found here.
The last sentence in your quote says "that is not otherwise specifically sequenced before or after the execution of the body of the called function" so the question is whether the increment and the assignment are "otherwise specifically sequenced before or after" the function body.
1.9 [intro.execution] p15 has the answer:
When calling a function (whether or not the function is inline), every value computation and side effect
associated with any argument expression, or with the postfix expression designating the called function, is
sequenced before execution of every expression or statement in the body of the called function. [ Note: Value
computations and side effects associated with different argument expressions are unsequenced. — end note ]
So the increment of i happens before the function body, and the assignment to i happens after the function returns, so it is perfectly well-defined.
In pre-C++11 terminology, the function call introduces a sequence point between the increment and the assignment.
i = foo(i++); is fine, because i++ is executed before foo() is called. A copy of i is made, i is then incremented, then the copy is passed to foo(). It is the same as doing this explicitly:
int tmp = i++;
i = foo(tmp);
Related
I am curious about initializer lists and sequence points. I read a while ago that the order of evaluation in initializer lists is left to right. If that is so, then there must be some kind of sequence point between the points of evaluation, am I wrong? So with that said is the following valid code? Is there anything that causes undefined behavior in it?
int i = 0;
struct S {
S(...) {}
operator int() { return i; }
};
int main() {
i = S{++i, ++i};
}
Any and all responses are appreciated.
Yes, the code is valid and does not have undefined behavior. Expressions in an initizalizer list are evaluated left-to-right and sequenced before the evaluation of the constructor of S. Therefore, your program should consistently assign value 2 to variable i.
Quoting § 8.5.4 of the C++ Standard:
"Within the initializer-list of a braced-init-list, the initializer-clauses, including any that result from pack expansions (14.5.3), are evaluated in the order in which they appear. That is, every value computation and side effect associated with a given initializer-clause is sequenced before every value computation and side effect associated with any initializer-clause that follows it in the comma-separated list of the initializer-list."
Thus, what happens is:
++i gets evaluated, yielding i = 1 (first argument of S's constructor);
++i gets evaluated, yielding i = 2 (second argument of S's constructor);
S's constructor is executed;
S's conversion operator is executed, returning value 2;
value 2 is assigned to i (which already had value 2).
Another relevant paragraph of the Standard is § 1.9/15, which also mentions similar examples that do have undefined behavior:
i = v[i++]; // the behavior is undefined
i = i++ + 1; // the behavior is undefined
However, the same paragraph says:
"Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [...] When calling a function (whether or not the function is inline), every value computation and side effect associated with any argument expression, or with the postfix expression designating the called function, is sequenced before execution of every expression or statement in the body of the called function."
Since 1) the evaluation of the expressions in the initializer list is sequenced left-to-right, 2) the execution of the constructor of S is sequenced after the evaluation of all expressions in the initializer list, and 3) the assignment to i is sequenced after the execution of the constructor of S (and its conversion operator), the behavior is well-defined.
Yes indeed you have case of undefined behavior.
Below are examples of situations causing undefined behavior:
A variable is changed several times within one sequence point. As a
canonical example, the i=i++ expression is often cited where
assignment of the i variable and its increment are performed at the
same time. To learn more about this kind of errors, read the section
"sequence points".
Using a variable before initializing it. Undefined behavior occurs
when trying to use the variable.
Memory allocation using the new [] operator and subsequent release
using the delete operator. For example: T *p = new T[10]; delete p;.
The correct code is: T *p = new T[10]; delete [] p;.
EDITED
Also your code S{++i, ++i}; is not compiled for VS2012. May be you mean S(++i, ++i);?
If you use "()" then undefined behavour is present. In other case your source code is incorrect.
map<int, int> mp;
printf("%d ", mp.size());
mp[10]=mp.size();
printf("%d\n", mp[10]);
This code yields an answer that is not very intuitive:
0 1
I understand why it happens - the left side of the assignment returns reference to mp[10]'s underlying value and at the same time creates aforementioned value, and only then is the right side evaluated, using the newly computed size() of the map.
Is this behaviour stated anywhere in C++ standard? Or is the order of evaluation undefined?
Result was obtained using g++ 5.2.1.
Yes, this is covered by the standard and it is unspecified behavior. This particular case is covered in a recent C++ standards proposal: N4228: Refining Expression Evaluation Order for Idiomatic C++ which seeks to refine the order of evaluation rules to make it well specified for certain cases.
It describes this problem as follows:
Expression evaluation order is a recurring discussion topic in the C++
community. In a nutshell, given an expression such as f(a, b,
c), the order in which the sub-expressions f, a, b, c are evaluated is left unspecified by the standard. If any two of these sub-expressions happen to modify the same object without intervening sequence points, the behavior of the program is undefined. For instance, the expression f(i++, i) where i is an
integer variable leads to undefined behavior , as does v[i]
= i++. Even when the behavior is not undefined, the result of evaluating an expression can still be anybody’s guess. Consider
the following program fragment:
#include <map>
int main() {
std::map<int, int> m;
m[0] = m.size(); // #1
}
What should the map object m look like after evaluation of the
statement marked #1? { {0, 0 } } or {{0, 1 } } ?
We know that unless specified the evaluations of sub-expressions are unsequenced, this is from the draft C++11 standard section 1.9 Program execution which says:
Except where noted, evaluations of operands of individual operators
and of subexpressions of individual expressions are unsequenced.[...]
and all the section 5.17 Assignment and compound assignment operators [expr.ass] says is:
[...]In all cases, the assignment is sequenced after the value
computation of the right and left operands, and before the value computation of the assignment expression.[...]
So this section does not nail down the order of evaluation but we know this is not undefined behavior since both operator [] and size() are function calls and section 1.9 tells us(emphasis mine):
[...]When calling a function (whether or not the function is inline), every value computation and side effect
associated with any argument expression, or with the postfix expression designating the called function, is
sequenced before execution of every expression or statement in the body of the called function. [ Note: Value
computations and side effects associated with different argument expressions are unsequenced. —end note ]
Every evaluation in the calling function (including other function calls) that is not otherwise specifically
sequenced before or after the execution of the body of the called function is indeterminately sequenced with
respect to the execution of the called function.9[...]
Note, I cover the second interesting example from the N4228 proposal in the question Does this code from “The C++ Programming Language” 4th edition section 36.3.6 have well-defined behavior?.
Update
It seems like a revised version of N4228 was accepted by the Evolution Working Group at the last WG21 meeting but the paper(P0145R0) is not yet available. So this could possibly no longer be unspecified in C++17.
Update 2
Revision 3 of p0145 made this specified and update [expr.ass]p1:
The assignment operator (=) and the compound assignment operators all group right-to-left.
All require a modifiable lvalue as their left operand; their result is an lvalue referring to the left operand.
The result in all cases is a bit-field if the left operand is a bit-field.
In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression. The right operand is sequenced before the left operand. ...
From the C++11 standard (emphasis mine):
5.17 Assignment and compound assignment operators
1 The assignment operator (=) and the compound assignment operators all group right-to-left. All require a modifiable lvalue as their left operand and return an lvalue referring to the left operand. The result in all cases is a bit-field if the left operand is a bit-field. In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression.
Whether the left operand is evaluated first or the right operand is evaluated first is not specified by the language. A compiler is free to choose to evaluate either operand first. Since the final result of your code depends on the order of evaluation of the operands, I would say it is unspecified behavior rather than undefined behavior.
1.3.25 unspecified behavior
behavior, for a well-formed program construct and correct data, that depends on the implementation
I'm sure that the standard does not specify for an expression x = y; which order x or y is evaluated in the C++ standard (this is the reason why you can't do *p++ = *p++ for example, because p++ is not done in a defined order).
In other words, to guarantee order x = y; in a defined order, you need to do break it up into two sequence points.
T tmp = y;
x = tmp;
(Of course, in this particular case, one might presume the compiler prefers to do operator[] before size() because it can then store the value directly into the result of operator[] instead of keeping it in a temporary place, to store it later after operator[] has been evaluated - but I'm pretty sure the compiler doesn't NEED to do it in that order)
Let's take a look at what your code breaks down to:
mp.operator[](10).operator=(mp.size());
which pretty much tells the story that in the first part an entry to 10 is created and in the second part the size of the container is assigned to the integer reference in position of 10.
But now you get into the order of evaluation problem which is unspecified. Here is a much simpler example .
When should map::size() get called, before or after map::operator(int const &); ?
Nobody really knows.
This question already has answers here:
What is the correct answer for cout << a++ << a;?
(4 answers)
Closed 7 years ago.
#include <iostream>
using namespace std;
int main()
{
int x=80;
int &y=x;
cout<<"x"<<x<<" "<<"y"<<y++;
return 0;
}
The above code gave me the following output:
81 80
Can anyone explain me how the value of x changes to 81? The value of y is 80 and it later gets incremented to 81, but how did it reflect in x?
Did it reflect because y is a reference variable? Then the value should have been modified in both x and y?
You have undefined behaviour because your operations are between two consecutive sequence points (there are no sequence points between function arguments evaluation). You can loosely think of sequence points as "temporal" markers and between two consecutive ones you are not allowed to modify the same variable more than once.
Basically your code is equivalent to
std::cout << x << x++; // undefined behaviour
since y is just a reference (an alias) for x.
1.9 Program execution [intro.execution] (emphasize mine)
14) Every value computation and side effect associated with a
full-expression is sequenced before every value computation and side
effect associated with the next full-expression to be evaluated.
15) 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, and they are not potentially concurrent (1.10),
the behavior is undefined. [ Note: The next section imposes similar,
but more complex restrictions on potentially concurrent computations.
—endnote]
When calling a function (whether or not the function is inline), every
value computation and side effect associated with any argument
expression, or with the postfix expression designating the called
function, is sequenced before execution of every expression or
statement in the body of the called function. [ Note: Value
computations and side effects associated with different argument
expressions are unsequenced. — end note ] Every evaluation in the
calling function (including other function calls) that is not
otherwise specifically sequenced before or after the execution of the
body of the called function is indeterminately sequenced with respect
to the execution of the called function.9 Several contexts in C++
cause evaluation of a function call, even though no corresponding
function call syntax appears in the translation unit. [ Example:
Evaluation of a new-expression invokes one or more allocation and
constructor functions; see 5.3.4. For another example, invocation of a
conversion function (12.3.2) can arise in contexts in which no
function call syntax appears.
Related: https://stackoverflow.com/a/10782972/3093378
With the new college year upon us.
We have started to receive the standard why does ++ i ++ not work as expected questions.
After just answering one of these type of questions I was told that the new C++11 standard has changed and this is no longer undefined behavior. I have heard that sequence points have been replaced by sequenced before and sequenced after but have not read deep (or at all) into the subject.
So the question I was just answering had:
int i = 12;
k = ++ (++ i);
So the question is:
How has the sequence points changes in C++11 and how does it affect questions like the above. Is it still undefined behavior or is this now well defined?
The UB in those cases is based on [intro.execution]/15
Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [...] 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.
For ++(++i): [expr.pre.incr]/1 states that ++i is defined as i+=1. This leads to [expr.ass]/1, which says
In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression.
Therefore, for ++(++i), equivalent to (i+=1)+=1, the inner assignment is sequenced before the outer assignment, and we have no UB.
[intro.execution]/15 has an example of UB:
i = i++ + 1; // the behavior is undefined
The case here is a bit different (thanks to Oktalist for pointing out a pre/postfix mistake here). [expr.post.incr]/1 describes the effects of postfix increment. It states:
The value computation of the ++ expression is sequenced before the modification of the operand object.
However, there is no requirement on the sequencing of the side effect (the modification of i). Such a requirement could also be imposed by the assignment-expression. But the assignment-expression only requires the value computations (but not the side effects) of the operands to be sequenced before the assignment. Therefore, the two modifications via i = .. and i++ are unsequenced, and we get undefined behaviour.
N.B. i = (i = 1); does not have the same problem: The inner assignment guarantees the side effect of i = 1 is sequenced before the value computation of the same expression. And the value is required for the outer assignment, which guarantees that it (the value computation of the right operand (i = 1)) is sequenced before the side effect of the outer assignment. Similarly, i = ++i + 1; (equivalent to i = (i+=1) + 1;) has defined behaviour.
The comma operator is an example where the side effects are sequenced; [expr.comma]/1
Every value computation and side effect associated with the left expression is sequenced before every value computation and side effect associated with the right expression.
[intro.execution]/15 includes the example i = 7, i++, i++; (read: (i=7), i++, i++;), which is defined behaviour (i becomes 9).
I don't think sequencing is relevant to your situation. The expression ++i++ is grouped as ++(i++), so:
If i is a built-in type, then this is invalid, since i++ is an rvalue.
If i is of user-defined type and the operators are overloaded, this is a nested function call, such as T::operator++(T::operator++(i), 0), and function arguments are evaluated before the function call is evaluated.
This is what i have coded today
#include <iostream>
using namespace std;
int function1()
{
cout<<"hello from function1()"; return 0;
}
int function2()
{
cout<<"hello from function2()"; return 0;
}
int main()
{
int func_diffresult = 0;
func_diffresult = function1() - function2();
cout<<func_diffresult; /** prints 0 correctly **/
}
the output is get is hello from function2()hello from function1(). I think the output should be hello from function1()hello from function2(). Is my compiler playing with me?
The order of evaluation of arguments of - operator is unspecified. So functions may be called in either order.
The - operator effectively becomes operator-(function1(), function2()), and the order of evaluation of function parameters is deliberately unspecified.
Related notes:
One really good reason to leave it unspecified is to handle calling conventions efficiently. For example, the C calling convention requires parameters be pushed on the stack in reverse order.
Therefore, it makes sense to evaluate the functions in reverse order since the result may be pushed immediately. To evaluate parameters from left-to-right and then push the results from right-to-left involves storing all results before pushing any of them. If you really need to do this, you can do it manually. If it doesn't matter to you, the performance benefit probably does.
The ISO standards does not guarantee the order in which subexpressions will be evaluated.
From the c++0x draft standard:
1.9. Program execution:
:
13/ Sequenced before is an asymmetric, transitive, pair-wise relation between evaluations executed by a single thread, which induces a partial order among those evaluations. Given any two evaluations A and B, if A is sequenced before B, then the execution of A shall precede the execution of B. 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.]
Evaluations A and B are indeterminately sequenced when either A is sequenced before B or B is sequenced before A, but it is unspecified which. [Note: Indeterminately sequenced evaluations cannot overlap, but either could be executed first.]
:
15/ Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.
:
When calling a function (whether or not the function is inline), every value computation and side effect associated with any argument expression, or with the postfix expression designating the called function, is sequenced before execution of every expression or statement in the body of the called function [Footnote: In other words, function executions do not interleave with each other]. [Note: Value computations and side effects associated with different argument expressions are unsequenced.]
Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function.
In other words, the implementation is free to arrange the calls using whatever method it desires. However, function calls are treated specially as per the footnote - they do not interleave.