Is this code behavior defined?
What does the following code print to the console?
map<i开发者_StackOverflow中文版nt,int> m;
m[0] = m.size();
printf("%d", m[0]);
Possible answers:
- The behavior of the code is not defined since it is not defined which statement
m[0]
orm.size()
is being executed first by the compiler. So it could print1
as well as0
. - It prints
0
because the right hand side of the assignment operator is executed first. It prints
1
because theoperator[]
has the highest priority of the complete statementm[0] = m.size()
. Because of this the following sequence of events occurs:m[0]
creates a new element in the mapm.size()
gets called which is now1
m[0]
gets assigned the previously returned (by m.size())1
The real answer?, which is unknown to me^^
I believe it's unspecified whether 0 or 1 is stored in m[0]
, but it's not undefined behavior.
The LHS and the RHS can occur in either order, but they're both function calls, so they both have a sequence point at the start and end. There's no danger of the two of them, collectively, accessing the same object without an intervening sequence point.
The assignment is actual int assignment, not a function call with associated sequence points, since operator[]
returns T&
. That's briefly worrying, but it's not modifying an object that is accessed anywhere else in this statement, so that's safe too. It's accessed within operator[]
, of course, where it is initialized, but that occurs before the sequence point on return from operator[]
, so that's OK. If it wasn't, m[0] = 0;
would be undefined too!
However, the order of evaluation of the operands of operator=
is not specified by the standard, so the actual result of the call to size()
might be 0 or 1 depending which order occurs.
The following would be undefined behavior, though. It doesn't make function calls and so there's nothing to prevent size
being accessed (on the RHS) and modified (on the LHS) without an intervening sequence point:
int values[1];
int size = 0;
(++size, values[0] = 0) = size;
/* fake m[0] */ /* fake m.size() */
It does print 1, and without raising a warning(!) using gcc. It should raise a warning because it is undefined.
The precedence class of both operator[]
and operator.
is 2 whereas the precedence class of operator=
is 16.
This means that it is well-defined that m[0]
and m.size()
will be executed before the assignment. However, it is not defined which one executes first.
There is no sequence point between the call to operator []
and the call to clear
in this statement. Consequently, the behaviour should be undefined.
Given that C++17 is pretty much here, I think it's worth mentioning that this code now exhibits well defined behavior under the new standard. For this case of =
being the built-in assignment to an integer:
[expr.ass]/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. The right operand is sequenced before the left operand. With respect to an indeterminately-sequenced function call, the operation of a compound assignment is a single evaluation.
Which leaves us with only one option, and that is #2.
精彩评论