这是代码行为定义?
以下代码打印到控制台是什么?
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]
在地图中创build一个新的元素 -
m.size()
被调用,现在是1
-
m[0]
被赋予先前返回的(由m.size())1
-
-
真正的答案? ,这是我不知道的^^
我相信没有指定 0或1是否存储在m[0]
,但不是未定义的行为。
LHS和RHS可以按任何顺序出现,但是它们都是函数调用,所以它们在开始和结束时都有一个序列点。 这两个人没有共同的危险,没有一个干预的顺序点访问同一个对象。
赋值是实际的int赋值,而不是与相关序列点的函数调用,因为operator[]
返回T&
。 这简短令人担忧,但它不会修改在此语句中任何地方访问的对象,所以这也是安全的。 它在operator[]
访问,当然,在它被初始化的地方被访问,但是在从operator[]
返回的序列点之前出现,所以没关系。 如果不是, m[0] = 0;
也将是不明确的!
然而, operator=
的操作数的求值顺序并不是标准规定的,所以调用size()
的实际结果可能是0或1,具体取决于哪个顺序发生。
但是,以下将是未定义的行为。 它不会进行函数调用,所以没有任何东西可以阻止访问size
(在RHS上)和修改(在LHS上)没有干预序列点:
int values[1]; int size = 0; (++size, values[0] = 0) = size; /* fake m[0] */ /* fake m.size() */
它打印1,而不用gcc提出警告(!)。 它应该提出警告,因为它是不确定的。
operator[]
和operator.
的优先级operator.
是2,而operator=
的优先级是16。
这意味着它是明确的m[0]
和m.size()
将在分配之前执行。 但是,没有定义哪一个先执行。
在调用operator []
和clear
调用之间没有顺序点 。 因此,行为应该是不确定的。
鉴于C ++ 17在这里,我认为值得一提的是,这个代码现在在新标准下展现出明确定义的行为。 对于这种情况=
是内置赋值给一个整数:
[expr.ass] / 1 :
赋值运算符(=)和复合赋值运算符全部从右到左。 所有需要一个可修改的左值作为它们的左操作数,并返回一个左值指向左操作数。 如果左操作数是位域,则所有情况下的结果都是一个位域。 在任何情况下,赋值都是在左右操作数的值计算之后,赋值expression式的值计算之前进行sorting的。 右操作数在左操作数之前sorting。 对于一个不确定sorting的函数调用,复合赋值的操作是一个单独的评估。
这使我们只有一个select,那就是#2。