这是代码行为定义?

以下代码打印到控制台是什么?

map<int,int> m; m[0] = m.size(); printf("%d", m[0]); 

可能的答案:

  1. 代码的行为没有被定义,因为它没有定义编译器首先执行m[0]m.size()哪个语句。 所以它可以打印1以及0
  2. 它打印0是因为赋值运算符的右侧首先被执行。
  3. 它打印1因为operator[]具有完整语句m[0] = m.size()的最高优先级。 因此,发生以下一系列事件:

    • m[0]在地图中创build一个新的元素
    • m.size()被调用,现在是1
    • m[0]被赋予先前返回的(由m.size()) 1
  4. 真正的答案? ,这是我不知道的^^

我相信没有指定 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。