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 ++ 17的左侧之前排序,而在它之前是不确定的顺序。并且gcc正确编译代码,v[0] == 1
在该任务之后。
然而,它也是不应该写的可怕代码,所以虽然警告的具体措辞是错误的,但警告的实际精神对我来说似乎很好。至少,我不打算提交有关它的错误报告,这似乎不值得开发人员有时间修复。因人而异。
[我在下面留下我的答案供参考,但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