Значение перезаписи RVO в параметре перед возвратом

Компиляция следующего с xlC в AIX приводит к созданию кода, который печатает "2 2". В Linux с gcc и clang он надежно создает "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 инициализированным по умолчанию x.

Я вызываю здесь какое-то поведение undefined? Я ожидал бы, что никаких изменений в a не будет до тех пор, пока combine(a, b) не будет оценен и не назначен a.

Это: IBM XL C/С++ для AIX, V12.1 (5765-J02, 5725-C72) Версия: 12.01.0000.0012

Ответ 1

Похоже, что компилятор выполняет копирование по назначению копирования (!), где это действительно может сделать только при инициализации. Это означает, что компилятор действительно перезаписывает объект, связанный с вашим параметром a при инициализации x. Наличие приложения RVO (для некоторого определения RVO) к возвращаемому значению combine само по себе не является неправильным. То, что не так, является целью RVO (который должен быть временным в области make, а не объектом, связанным с a в make).

Добавление предоставленного пользователем оператора присваивания копии должно работать как обходное решение:

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