以下代码如何打印到控制台?
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
真正的答案?,我不知道^^
答案 0 :(得分:17)
我认为未指定是否在m[0]
中存储0或1,但它不是未定义的行为。
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 :(得分:2)
此语句中对operator []
的调用与clear
的调用之间没有sequence point。因此,行为应未定义。
答案 2 :(得分:2)
打印1,而不使用gcc发出警告(!)。 应提出警告,因为它未定义。
operator[]
和operator.
的优先级为2,而operator=
的优先级为16。
这意味着定义良好,m[0]
和m.size()
将在分配之前执行。但是,没有定义首先执行哪一个。
答案 3 :(得分:1)
鉴于C ++ 17几乎就在这里,我认为值得一提的是,此代码现在在新标准下表现出明确的行为。对于=
作为整数的内置赋值的情况:
赋值运算符(=)和复合赋值运算符all 小组从右到左。所有都需要左侧可修改的左值 操作数并返回一个引用左操作数的左值。结果 在所有情况下,如果左操作数是位字段,则是位字段。在所有 在这种情况下,赋值在值的计算之后排序 左右操作数,以及之前的值计算 赋值表达式。 右操作数在左前排序 操作数。关于不确定顺序的函数调用, 复合赋值的操作是单一的评估。
这使我们只有一个选项,那就是#2。