C++17 排序:作业左侧的后递增

C++17 sequencing: post-increment on left side of assignment

本文关键字:排序 作业 C++17      更新时间:2023-10-16

C++17标准通过一条规则修订了C++语言的操作顺序的定义,大意如下:

在每个简单的赋值表达式中 E1=E2 和每个化合物 赋值表达式 E1@=E2,每个值计算和副作用 的 E2 在每次值计算和副作用之前进行排序 E1

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

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++17 中,右侧先于左侧排序,而在它之前则不确定地排序。gcc 正确编译代码,v[0] == 1在分配之后。

然而,这也是不应该编写的糟糕代码,所以虽然警告的具体措辞是错误的,但警告的实际精神对我来说似乎很好。至少,我不打算提交有关它的错误报告,而且它似乎不是值得开发人员花时间修复的那种事情。扬子晚报.

[我将我的答案留在下面以供参考,但进一步的讨论表明,我下面的答案是不完整的,其结论最终是不正确的。

C++17标准(此处为草案(,[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。您可能已经发现了该标准的一个重要问题。当你有时间时,报告它。

更新

@SombreroChicken补充说:

这只是因为GCC 6.3还没有正确实现C++17。从 7.1 及更高版本开始,它首先评估正确,如下所示。

输出:

in right() ...
in left () ...
6