C ++ 17排序:赋值左侧的后增量

问题描述 投票:4回答:2

C ++ 17标准通过规则stating, to the effect修改了C ++语言的操作顺序的定义:

在每个简单赋值表达式E1 = E2和每个复合赋值表达式E1 @ = E2中,E2的每个值计算和副作用在E1的每个值计算和副作用之前被排序。

但是,在使用-std=c++17-Wall在GCC 8.1中编译以下代码时

int v[] { 0,1,2,3,4,5,6,7 };
int *p0 = &v[0];
*p0++ = *p0 + 1;
cout << "v[0]: " << v[0] << endl;

我收到以下警告:

main.cpp:266:8: warning: operation on 'p0' may be undefined [-Wsequence-point]
     *p0++ = *p0 + 1;
      ~~^~

输出是:

v[0]: 1

问题是:警告是错误的吗?

c++ c++17 assignment-operator order-of-evaluation
2个回答
7
投票

问题是:警告是错误的吗?

这取决于。

从技术上讲,有问题的代码是明确定义的。右侧在C ++ 17的左侧之前排序,而在它之前是不确定的顺序。并且gcc正确编译代码,v[0] == 1在该任务之后。

然而,它也是不应该写的可怕代码,所以虽然警告的具体措辞是错误的,但警告的实际精神对我来说似乎很好。至少,我不打算提交有关它的错误报告,这似乎不值得开发人员有时间修复。因人而异。


0
投票

[我在下面留下我的答案供参考,但further discussion表明我的答案不完整,其结论最终是不正确的。]

C ++ 17标准(草案here),[expr.ass]确实如下:

[赋值运算符]的右操作数在左操作数之前排序。

这对我来说听起来和对你一样都是错误的。 @Barry不喜欢你的示例代码,为了避免分散注意力,我测试了替代代码:

#include <iostream>

namespace {
    int a {3};

    int& left()
    {
        std::cout << "in left () ...\n";
        return ++a;
    }

    int right()
    {
        std::cout << "in right() ...\n";
        return a *= 2;
    }
}

int main()
{
    left() = right();
    std::cout << a << "\n";
    return 0;
}

输出(使用GCC 6.3):

in left () ...
in right() ...
8

无论你是看打印的消息还是考虑计算出的值8,看起来好像左操作数在右操作数之前排序 - 这是有意义的,只要有效的机器代码

  • 通常应该更喜欢决定存储计算结果的位置
  • 在实际计算结果之前。

我不同意@Barry。您可能已经发现了标准的一个重要问题。如果你有时间,请报告。

UPDATE

@SombreroChicken补充道:

那只是因为GCC 6.3还没有正确实现C ++ 17。从7.1开始,它首先评估正确的here.

输出:

in right() ...
in left () ...
6
© www.soinside.com 2019 - 2024. All rights reserved.