此代码行为是否已定义?
以下代码将什么打印到控制台?
map<int,int> m;
m[0] = m.size();
printf("%d", m[0]);
可能的答案:
- 代码的行为未定义,因为未定义编译器首先执行哪个语句
m[0]
或m.size()
。因此它可以打印1
以及0
。 - 它打印
0
因为赋值运算符的右侧首先被执行。 它打印
1
,因为operator[]
具有完整语句的最高优先级m[0] = m.size()
。因此,会发生以下事件序列:m[0]
在地图中创建一个新元素m.size()
被调用,现在是1
m[0]
被分配先前返回的值(通过 m.size())1
真正的答案?,我不知道^^
What does the following code print to the console?
map<int,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^^
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我相信未指定是否将0或1存储在
m[0]
中,但这不是未定义的行为。LHS 和 RHS 可以按任一顺序发生,但它们都是函数调用,因此它们在开始和结束处都有一个序列点。他们两个共同访问同一个对象而没有中间序列点,不存在危险。
该赋值是实际的 int 赋值,而不是具有关联序列点的函数调用,因为
operator[]
返回T&
。这有点令人担忧,但它不会修改此语句中其他任何地方访问的对象,因此这也是安全的。当然,它是在operator[]
内进行访问的,在它初始化的地方,但是发生在从operator[]
返回时的序列点之前,所以没关系。如果不是,m[0] = 0;
也将是未定义的!但是,标准并未指定
operator=
操作数的求值顺序,因此调用size()
的实际结果可能是 0 或 1,具体取决于发生哪个顺序。不过,以下内容将是未定义的行为。它不会进行函数调用,因此没有什么可以阻止在没有插入序列点的情况下访问(在右侧)和修改(在左侧)
size
: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[]
returnsT&
. 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 withinoperator[]
, of course, where it is initialized, but that occurs before the sequence point on return fromoperator[]
, 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 tosize()
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:它确实打印 1,并且不会使用 gcc 发出警告(!)。它应该发出警告,因为它是未定义的。
operator[]
和operator.
的优先级均为 2,而operator=
的优先级为 16。这意味着明确定义了
m[0]
和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[]
andoperator.
is 2 whereas the precedence class ofoperator=
is 16.This means that it is well-defined that
m[0]
andm.size()
will be executed before the assignment. However, it is not defined which one executes first.在对
operator []
的调用和在此语句中调用clear
。因此,行为应该是未定义的。There is no sequence point between the call to
operator []
and the call toclear
in this statement. Consequently, the behaviour should be undefined.鉴于 C++17 已经差不多了,我认为值得一提的是,这段代码现在在新标准下表现出了明确定义的行为。对于
=
是对整数的内置赋值的情况:[expr.ass]/1:
这让我们只有一个选择,那就是#2。
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:
Which leaves us with only one option, and that is #2.