C++17 排序:作业左侧的后递增
C++17 sequencing: post-increment on left side of assignment
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
- 二叉排序树无法编译
- 仅使用绝对值对数组进行排序,并在C++中显示实际值
- C++选择排序算法中的逻辑错误
- 使用C++程序合并排序没有得到正确的输出
- 计算排序向量的向量中唯一值的计数
- 排序算法c++
- 使用2个键的cpp-stl::优先级队列排序不正确
- 将结构向量排序为子组
- 在c++中尝试对对象数组进行排序时,出现std:bad_alloc错误
- 如何对点云数据进行排序
- 对字符串进行排序时,在c++中处理sort()
- 是否有类似std::lower_bound的函数,而不需要排序/分区输入
- 下面是排序算法O(n)吗
- std::sort()函数无法对向量的一部分进行排序
- C++17 排序:作业左侧的后递增
- 家庭作业的排序链表程序中的分段错误
- 数组列表、行搜索和气泡排序.作业C++
- 使合并排序几乎与家庭作业的伪代码相同
- 插入排序作业
- 如何确定作业中的两个副作用是否未排序