以下は、書籍「C++ Gotchas」の項目 56 からの抜粋です。
Y オブジェクトの単純な初期化が、3 つの異なる方法のいずれかであるかのように記述されることは珍しくありません。
Y a( 1066 );
Y b = Y(1066);
Y c = 1066;
実際のところ、これら 3 つの初期化はすべて同じオブジェクト コードが生成される可能性がありますが、同等ではありません。a の初期化は直接初期化として知られており、期待通りの動作をします。初期化は、Y::Y(int) の直接呼び出しによって実行されます。
b と c の初期化はより複雑です。実際、それらは複雑すぎます。これらは両方ともコピーの初期化です。b の初期化の場合、値 1066 で初期化された、タイプ Y の匿名一時の作成を要求しています。次に、この匿名一時を、クラス Y のコピー コンストラクターへのパラメーターとして使用して、b を初期化します。最後に、匿名のテンポラリのデストラクタを呼び出します。
これをテストするために、データ メンバ (最後に添付されたプログラム) を使用して単純なクラスを作成したところ、驚くべき結果が得られました。c の場合、本で示唆されているのではなく、コピー コンストラクターによってオブジェクトが構築されたようです。
言語標準が変更されたのか、それとも単にコンパイラの最適化機能なのか、誰か知っていますか? Visual Studio 2008 を使用していました。
コードサンプル:
#include <iostream>
class Widget
{
std::string name;
public:
// Constructor
Widget(std::string n) { name=n; std::cout << "Constructing Widget " << this->name << std::endl; }
// Copy constructor
Widget (const Widget& rhs) { std::cout << "Copy constructing Widget from " << rhs.name << std::endl; }
// Assignment operator
Widget& operator=(const Widget& rhs) { std::cout << "Assigning Widget from " << rhs.name << " to " << this->name << std::endl; return *this; }
};
int main(void)
{
// construct
Widget a("a");
// copy construct
Widget b(a);
// construct and assign
Widget c("c");
c = a;
// copy construct!
Widget d = a;
// construct!
Widget e = "e";
// construct and assign
Widget f = Widget("f");
return 0;
}
出力:
Constructing Widget a
Copy constructing Widget from a
Constructing Widget c
Assigning Widget from a to c
Copy constructing Widget from a
Constructing Widget e
Constructing Widget f
Copy constructing Widget from f
私が最も驚いたのは、d と e を構築した結果です。正確には、空のオブジェクトが作成され、次にオブジェクトが作成されて空のオブジェクトに割り当てられることを期待していました。実際には、オブジェクトはコピー コンストラクターによって作成されました。