私は、コピー省略、RVO、NRVO のケースとは別に、いつコピーが実行されるかを確認するためにいくつかの実験を行っていました。
そこで、次のようなコードを書きました。
class X {
public:
X() { std::cout << "Default constructor" << std::endl; }
X(const X&) { std::cout << "Copy constructor" << std::endl; }
X(X&&) { std::cout << "Move constructor" << std::endl; }
X& operator=(const X) {
std::cout << "Assignment operator" << std::endl;
return *this;
}
X& operator=(X&&) {
std::cout << "Move assignment operator" << std::endl;
return *this;
}
~X() { std::cout << "Destructor" << std::endl; }
};
class Y {
private:
X x;
public:
const X& getX() const {
std::cout << "getX" << std::endl;
return x;
}
};
int main() {
Y y;
std::cout << "assign to ref" << std::endl;
const X& x1 = y.getX();
(void)x1;
std::cout << "assign to const" << std::endl;
const X x2 = y.getX();
return 0;
}
出力として以下を受け取ります。
Default constructor
assign to ref
getX
assign to const
getX
Copy constructor
Destructor
Destructor
-O3 を使用して gcc または clang でコンパイルし、 -std=c++{11,14,17} を試した場合、両方とも同じ出力が生成されました。
驚いたことに、y.getX(); を使用するときにコピーが実行されるとは思っていませんでした。const 変数に。これは、次のコードでその変数とそのメンバーへのアクセスを容易にするために頻繁に使用したものですが、const 参照ではなく、コンパイラーが名前変更と見なすことを期待して const を使用していました。
そのコピーが正確に実行される理由を誰かが知っていますか? 私の頭に浮かぶ唯一の理由は、コードをスレッドセーフにすることです。オブジェクト y を操作するスレッドが複数ある場合、const への割り当ては結局その const にはなりません。オブジェクトyのメンバーxを参照するだけなので。他のスレッドによって変更される可能性があります。しかし、それが本音かどうかはわかりません。