C++17 排序:post-赋值左侧递增
C++17 sequencing: post-increment on left side of assignment
C++17 标准通过规则修改了 C++ 语言的操作顺序定义 stating, to the effect:
In every simple assignment expression E1=E2 and every compound
assignment expression E1@=E2, every value computation and side-effect
of E2 is sequenced before every value computation and side effect of
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
问题是:警告有误吗?
And the question: is the warning erroneous?
视情况而定。
从技术上讲,相关代码定义明确。在 C++17 中,右侧先于左侧排序,而之前是不确定排序。 gcc 正确编译代码,v[0] == 1
在赋值后。
然而,这也是不应该编写的可怕代码,所以虽然警告的具体措辞是错误的,但警告的实际精神对我来说似乎很好。至少,我不会提交关于它的错误报告,而且它似乎不值得开发人员花时间修复。 YMMV.
[我在下面留下我的答案以供参考,但 表明我在下面的答案不完整,其结论最终是不正确的。]
C++17 标准(草案here),[expr.ass],的确如此:
The right operand [of an assignment operator] is sequenced before the left operand.
这对我和你来说都是错误的。 @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 的计算值,它看起来好像 left 操作数在 right[=41= 之前排序] 操作数——这是有道理的,就高效的机器代码而言
- 通常应该更愿意决定在哪里存储计算结果
- 在实际计算结果之前。
我不同意@Barry。您可能发现了标准的一个重要问题。有空的时候报告一下。
更新
@SombreroChicken 补充道:
That's just because GCC 6.3 didn't correctly implement C++17 yet. From 7.1 and onwards it evaluates right first as seen here.
输出:
in right() ...
in left () ...
6
C++17 标准通过规则修改了 C++ 语言的操作顺序定义 stating, to the effect:
In every simple assignment expression E1=E2 and every compound assignment expression E1@=E2, every value computation and side-effect of E2 is sequenced before every value computation and side effect of E1
然而,当使用 -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
问题是:警告有误吗?
And the question: is the warning erroneous?
视情况而定。
从技术上讲,相关代码定义明确。在 C++17 中,右侧先于左侧排序,而之前是不确定排序。 gcc 正确编译代码,v[0] == 1
在赋值后。
然而,这也是不应该编写的可怕代码,所以虽然警告的具体措辞是错误的,但警告的实际精神对我来说似乎很好。至少,我不会提交关于它的错误报告,而且它似乎不值得开发人员花时间修复。 YMMV.
[我在下面留下我的答案以供参考,但
C++17 标准(草案here),[expr.ass],的确如此:
The right operand [of an assignment operator] is sequenced before the left operand.
这对我和你来说都是错误的。 @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 的计算值,它看起来好像 left 操作数在 right[=41= 之前排序] 操作数——这是有道理的,就高效的机器代码而言
- 通常应该更愿意决定在哪里存储计算结果
- 在实际计算结果之前。
我不同意@Barry。您可能发现了标准的一个重要问题。有空的时候报告一下。
更新
@SombreroChicken 补充道:
That's just because GCC 6.3 didn't correctly implement C++17 yet. From 7.1 and onwards it evaluates right first as seen here.
输出:
in right() ...
in left () ...
6