【问题标题】:RVO overwriting value in parameter before returnRVO 在返回前覆盖参数中的值
【发布时间】:2018-02-02 15:36:37
【问题描述】:

在 AIX 上使用 xlC 编译以下代码会生成打印“2 2”的代码。在带有 gcc 和 clang 的 Linux 上,它可靠地产生“3 3”。

#include <iostream>

struct Numbers
{
    Numbers() : a(0) , b(0) { } 
    Numbers(int a, int b) : a(a), b(b) { }

    int a;
    int b;
};

Numbers combine(const Numbers& a, const Numbers& b)
{
    Numbers x;
    x.a = a.a + b.a;
    x.b = a.b + b.b;
    return x;
}

Numbers make()
{
    Numbers a(1, 1);
    Numbers b(2, 2);

    a = combine(a, b);
    return a;
}

int main()
{
    Numbers a = make();
    std::cerr << a.a << " " << a.b << "\n";
}

在我看来,AIX 正在将 RVO 应用于 combine 的返回值,所以当我创建 Numbers x 时,它最终会用默认初始化的 x 覆盖我的参数 a

我在这里调用了一些未定义的行为吗?我希望在combine(a, b) 被评估并分配给a 之前,不会对a 进行任何修改。

这是与: 适用于 AIX 的 IBM XL C/C++,V12.1(5765-J02、5725-C72) 版本:12.01.0000.0012

【问题讨论】:

  • 我在这里看不到 UB。似乎是编译器错误。
  • 如果将std::cerr &lt;&lt; a.a &lt;&lt; " " &lt;&lt; a.b &lt;&lt; "\n"; 添加到make() 中会发生什么?
  • 你试过直接return combine(a, b);吗?
  • 那么肯定看起来像一个错误。
  • @Hamish Morrison 当他们回复您的错误报告时,请在此处发布结果。无论他们确认还是否认这是一个错误,回复对于未来看到此问题的用户来说都是有用的信息。

标签: c++ language-lawyer c++03


【解决方案1】:

看起来编译器正在对复制赋值(!)执行复制省略,它实际上只能在初始化时这样做。也就是说编译器在初始化x时确实覆盖了与你的参数a关联的对象。将 RVO(对于 RVO 的某些定义)应用到 combine 的返回值本身并没有错。问题是 RVO 的目标(它应该是 make 范围内的临时对象,而不是与 make 中的 a 关联的对象)。

添加用户提供的复制赋值运算符应该是一种解决方法:

Numbers &operator=(const Numbers &other) { a = other.a; b = other.b; return *this; }

【讨论】:

    猜你喜欢
    • 2020-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-26
    • 2016-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多