返回前RVO覆盖参数值

时间:2017-08-24 16:40:18

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

在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时,它最终会使用默认的初始值{{}覆盖我的参数a。 1}}。

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

这是: IBM XL C / C ++ for AIX,V12.1(5765-J02,5725-C72) 版本:12.01.0000.0012

1 个答案:

答案 0 :(得分:3)

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

添加用户提供的副本分配运算符应该可以解决方法:

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