C++では**直接初期化(direct)と間接初期化(copy)**のオブジェクトを区別します:
直接初期化:
MyClass obj(arg1, arg2); int x(5);
クラスに対して適切なコンストラクタを直接呼び出します。
間接初期化:
MyClass obj = MyClass(arg1, arg2); int x = 5;
一時オブジェクトを作成し、その後にコピー(またはムーブ)します(コピーコンストラクタまたはムーブコンストラクタを使用)。
違い:
例:
struct NonCopyable { NonCopyable(int) {} NonCopyable(const NonCopyable&) = delete; }; NonCopyable a(5); // OK: 直接 NonCopyable b = NonCopyable(5); // 最適化によりOK, C++17以前はエラー NonCopyable c = 5; // エラー: コピーコンストラクタが存在しない
"C++11が使用され、最適化されたコンパイラが有効の場合、copy-initializationはdirect-initializationより多くのコンストラクタ呼び出しを引き起こす可能性がありますか?"
回答: 理論的には、はい。コピーエリジョンがない場合、copy-initializationは一時オブジェクトを作成し、その後にコピーまたはムーブコンストラクタを呼び出します。direct-initializationは常に基本のコンストラクタのみを呼び出します。しかし、最適化が有効な最新のコンパイラ(C++17以降)は、保証されたコピーエリジョンによりこの違いを解消します。
逸話
金融プロジェクトでは、一時オブジェクトを伴うcopy-initializationを使用し、必要な型にコピーコンストラクタがありませんでした。アプリケーションは古いコンパイラ(C++17以前)でビルドされず、direct-initは動作しました。
逸話
データシリアル化ユーティリティでは、プログラマーはdirect-initとcopy-initが同等であると考えていました。その結果、大きな構造物の不要なコピーが発生し、パフォーマンスが低下しました。
逸話
ユーザーオブジェクトのグローバル配列の初期化時に、間接初期化を使用しました。エラーは、一時オブジェクトが発生しないプラットフォームでのみ現れ、ABIの特性により余分なコンストラクタの暗黙の呼び出しが発生しました。