2017-08-24 19 views
10

在AIX上使用xlC编译以下代码会导致打印“2 2”的代码。在使用gcc和clang的Linux上,它可靠地生成“3 3”。RVO在返回前覆盖参数中的值

#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使用默认初始化x

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

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

+6

我看不出这里UB。似乎是一个编译器错误。 – Jarod42

+0

如果将'std :: cerr << a.a <<“”<< a.b <<“\ n”;'添加到'make()'中会发生什么? – NathanOliver

+0

你试过'返回结合(a,b);'直接? – Jarod42

回答

3

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

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

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