ProgrammingC++開発者

C++におけるオブジェクトの直接初期化と間接初期化の違いは何ですか?組み込み型とユーザー定義型で作業する際の影響はどのようなものですか?

Hintsage AIアシスタントで面接を突破

回答

C++では**直接初期化(direct)と間接初期化(copy)**のオブジェクトを区別します:

  • 直接初期化:

    MyClass obj(arg1, arg2); int x(5);

    クラスに対して適切なコンストラクタを直接呼び出します。

  • 間接初期化:

    MyClass obj = MyClass(arg1, arg2); int x = 5;

    一時オブジェクトを作成し、その後にコピー(またはムーブ)します(コピーコンストラクタまたはムーブコンストラクタを使用)。

違い:

  1. 組み込み型の場合、動作は同じです。クラスの場合、呼び出されるコンストラクタのセットが異なる場合や、初期化が禁止されることがあります。
  2. メンバーの初期化リストは、コンパイラの要件により、異なる初期化方法に対して常に同等ではありません。
  3. コピーエリジョン(余分なコピーの削除を行うコンパイラによる最適化)は、しばしば違いを無効にします(ただし、特にC++17以前は常にそうではありません)。

例:

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の特性により余分なコンストラクタの暗黙の呼び出しが発生しました。