C++の関数の戻り値がカスタムクラスの場合、レプリケーションコンストラクタを呼び出さないという問題

6625 ワード

最近期末試験、復習で忙しくて、ACMはしばらく鳩になりました.復習中にプログラムを叩いてコンパイラがどのように構造関数を解析したのかを見たいと思っていたが、問題が発生した.問題はこうです.
#include 
using namespace std;
typedef long long ll;
class Complex
{
public:
    int r, i;
public:
    Complex(int a, int b): r(a), i(b) { cout << "Constructor called." << endl; }
    ~Complex() { cout << "Destructor called." << endl; }
    Complex(const Complex &a) { r = a.r, i = a.i; cout << "Copy constructor called." << endl; }
    Complex operator +(Complex x1);
};
Complex Complex::operator +(Complex x1)
{
    return Complex(r + x1.r, i + x1.i);
}
int main()
{
    Complex a(1, 2);
    a = a + a;
    return 0;
}

実行結果は次のとおりです.
Constructor called.
Copy constructor called.
Constructor called.
Destructor called.
Destructor called.
Destructor called.

本で述べたように、このプログラムはまず1回の構造関数を呼び出してオブジェクトaを作成し、その後、メインプログラムの2行目で複製構造関数を呼び出してaをパラメータx 1に渡し、その後、関数の中で1回の構造関数を呼び出して加算の結果を生成し、その後、1回の複製構造関数を呼び出してこの結果を一時オブジェクトに保存し、構造結果とx 1を分析し、その後,一時オブジェクトをaに割り当て,最後に一時オブジェクトを解析する.理想的な結果は次のとおりです.
Constructor called.
Copy constructor called.
Constructor called.
Copy constructor called.
Destructor called.
Destructor called.
Destructor called.
Destructor called.

しかし、プログラムの実行結果は、コンストラクション関数とコンストラクション関数の呼び出しを1回もコピーしないことが明らかになった.いろいろ考えて、ある午後、不思議なサザエに聞いてみると、C++は戻り値最適化というものがあることがわかりました.この記事では、C++の一時オブジェクトと戻り値の最適化について詳しく説明します.
具体的には,戻り値最適化には2つの実装方式がある.1つ目は既存のオブジェクトaに対して,呼び出し関数がそのオブジェクトに値を付与するのはコンパイラがこっそり関数にパラメータを1つ多く詰め,aのアドレスを転送し,その後直接関数にaを付与することである.第二に、このブログは詳しく書かれています.
プログラムの
a = a + a;

に改心
a + a;

レプリケーションコンストラクション関数は呼び出されませんでした.採用すべきは2つ目の方法です.
間違いがあったら指摘を歓迎します.