C++17 排序:赋值左侧的后增量
Posted
技术标签:
【中文标题】C++17 排序:赋值左侧的后增量【英文标题】:C++17 sequencing: post-increment on left side of assignment 【发布时间】:2019-03-16 16:20:14 【问题描述】:C++17标准通过stating, to the effect规则修改了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
问题是:警告是否错误?
【问题讨论】:
当然,标准表明*p0 + 1
将在左侧的任何内容之前进行评估。由于++
是后缀,因此无论是否对其进行评估都不会影响对v[0]
的分配。真正的问题是p0
现在是否指向v[1]
。
无警告here
@Jans 你要加-Wall
@Jans 您已关闭警告。添加-Wall
【参考方案1】:
问题是:警告是否错误?
视情况而定。
从技术上讲,有问题的代码定义明确。在 C++17 中,右侧排序在左侧之前,而在它之前是不确定排序的。并且 gcc 正确编译代码,v[0] == 1
在分配之后。
但是,这也是不应该编写的糟糕代码,因此虽然警告的具体措辞是错误的,但警告的实际精神对我来说似乎很好。至少,我不打算提交有关它的错误报告,而且它似乎不值得开发人员花时间修复。 YMMV。
【讨论】:
当然,“糟糕的代码”往往在旁观者的眼中。有些人认为A && B || C && D
是糟糕的代码,因为他们从未研究过形式逻辑,也没有“长大”隐含地知道连词总是比析取具有更高的优先级。其他人认为(A && B) || (C && D)
是糟糕的代码,因为括号的使用暗示了非标准的评估顺序。关键是这种表达感觉就像是糟糕的代码,因为它是几十年来 C++ 编码中根深蒂固的思想习惯,那就是 UB。但现在不是。所以曾经可怕的是现在优雅的语法。【参考方案2】:
[我在下面留下我的答案以供参考,但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,看起来好像 left 操作数在 right 操作数之前排序 - 这是有道理的,就目前而言作为高效的机器码
通常应该更愿意决定将计算结果存储在哪里 在实际计算结果之前。我不同意@Barry。您可能已经发现了该标准的一个重要问题。有时间就举报吧。
更新
@SombreroChicken 补充道:
那只是因为 GCC 6.3 还没有正确实现 C++17。从 7.1 起,它首先评估正确,如 here.
输出:
in right() ...
in left () ...
6
【讨论】:
那只是因为 GCC 6.3 还没有正确实现 C++17。从 7.1 开始,它首先评估正确,如下所示:wandbox.org/permlink/6OtnRcfOaxivYfN2 @thb “您可能已经发现标准的一个重要问题,”我认为您的意思是编译器? @SombreroChicken 您似乎在密切关注 [C++],所以我怀疑您可能已经看过它,但如果您还没有看过:您的启发性评论和测试运行现在引发了一个相关的问题,并且答案:In the expression left() = right(), why is right() sequenced first? @thb 是的,我看到了。那里有很好的问题和答案。以上是关于C++17 排序:赋值左侧的后增量的主要内容,如果未能解决你的问题,请参考以下文章