11

[この質問は高度に編集されています。申し訳ありませんが、編集を以下の回答に移動しました]

C ++ 11のウィキペディア(サブ記事を含む)から:

この [新しい委譲コンストラクター機能] には注意点があります。C++03 では、コンストラクターの実行が終了するとオブジェクトが構築されると見なされますが、C++11 では、コンストラクターの実行が終了するとオブジェクトが構築されると見なされます。複数のコンストラクターの実行が許可されるため、これは、各委任コンストラクターが独自の型の完全に構築されたオブジェクトで実行されることを意味します。派生クラス コンストラクターは、基本クラスの委任がすべて完了した後に実行されます。」

これは、委任チェーンが ctor 委任チェーン内のすべてのリンクに対して一意の一時オブジェクトを構築することを意味しますか? 単純な init 関数の定義を避けるためだけにかかるオーバーヘッドは、追加のオーバーヘッドに値しません。

免責事項: 私は学生なので、この質問をしましたが、これまでの回答はすべて正しくなく、研究不足および/または参照されている研究の理解が不足していることを示しています. 私はこれにいくらかイライラしており、その結果、私の編集やコメントは、ほとんどがスマートフォンを介して、急いで構成されていませんでした. 失礼します。以下の回答でそれを最小限に抑えたことを願っています。また、コメントでは注意し、完全で、明確にする必要があることを学びました。

4

4 に答える 4

4

いいえ、同等です。委任コンストラクターは、前のコンストラクターによって構築されたオブジェクトに作用する通常のメンバー関数のように動作します。

委任コンストラクターを追加するための提案でこれを明示的にサポートする情報を見つけることができませんでしたが、一般的なケースではコピーを作成することはできません。一部のクラスには、コピー コンストラクターがない場合があります。

セクション 4.3 - §15 の変更では、標準の変更案は次のように述べています。

オブジェクトの非委任コンストラクターが実行を完了し、そのオブジェクトの委任コンストラクターが例外で終了した場合、オブジェクトのデストラクタが呼び出されます。

これは、委任コンストラクターが完全に構築されたオブジェクトで機能し (定義方法に応じて)、実装が委任 ctor をメンバー関数のように機能させることを意味します。

于 2015-10-14T02:54:34.097 に答える
3

C++11 のチェーンされた委譲コンストラクターは、C++03 の init 関数スタイルよりも多くのオーバーヘッドを引き起こします!

C++11 標準ドラフトN3242のセクション 15.2 を参照してください。委譲チェーン内の任意のリンクの実行ブロックで例外が発生する可能性があり、C++11 はそれを考慮して既存の例外処理動作を拡張します。

[テキスト] と強調します。

初期化または破棄が例外によって終了する保存期間のオブジェクトでは、完全に構築されたすべてのサブオブジェクトに対してデストラクタが実行されます...つまり、プリンシパル コンストラクタ (12.6.2) が実行を完了し、デストラクタはまだ実行を開始していません。同様に、オブジェクトの非委任コンストラクターが実行を完了し、そのオブジェクトの委任コンストラクターが例外で終了した場合、オブジェクトの [上記のようにサブオブジェクトのように扱われる] デストラクタが呼び出されます。

これは、委任された ctor の C++ オブジェクト スタック モデルとの一貫性を説明しているため、必然的にオーバーヘッドが発生します。

ハードウェア レベルでスタックがどのように機能するか、スタック ポインターとは何か、自動オブジェクトとは何か、スタックの巻き戻しとは何かなどをよく理解して、これがどのように機能するかを理解する必要がありました。技術的には、これらの用語/概念は実装で定義された詳細であるため、N3242 はこれらの用語を定義していません。しかし、それはそれらを使用します。

その要点: スタック上で宣言されたオブジェクトがメモリに割り当てられ、実行可能ファイルがアドレス指定とクリーンアップを処理します。スタックの実装は C では単純でしたが、C++ では例外があり、C のスタック巻き戻しの拡張が必要です。Stroustrup * による論文のセクション 5では、拡張されたスタックの巻き戻しの必要性と、そのような機能によって導入される必要な追加のオーバーヘッドについて説明しています。

ローカル オブジェクトにデストラクタがある場合、そのデストラクタをスタックの巻き戻しの一部として呼び出す必要があります。[自動オブジェクトのスタック巻き戻しの C++ 拡張が必要] ...(ハンドラーを確立する標準的なオーバーヘッドに加えて) 最小限のオーバーヘッドのみを含む実装手法。

委任チェーン内のすべてのリンクのコードに追加するのは、まさにこの実装手法とオーバーヘッドです。すべてのスコープには例外の可能性があり、すべてのコンストラクターには独自のスコープがあるため、チェーン内のすべてのコンストラクターはオーバーヘッドを追加します (追加のスコープを 1 つだけ導入する init 関数と比較して)。

オーバーヘッドが最小限であることは事実です。適切な実装では、単純なケースを最適化してそのオーバーヘッドを取り除くことができると確信しています。ただし、5 つのクラスの継承チェーンがある場合を考えてみましょう。これらのクラスのそれぞれに 5 つのコンストラクターがあり、各クラス内で、これらのコンストラクターが連鎖して相互に呼び出し、冗長なコーディングを削減するとします。最も派生したクラスのインスタンスをインスタンス化すると、上記のオーバーヘッドが最大25回発生しますが、C++03 バージョンではそのオーバーヘッドが最大10回発生します。回。これらのクラスを仮想化して多重継承すると、これらの機能の蓄積に関連してこのオーバーヘッドが増加し、それらの機能自体が追加のオーバーヘッドを導入します。ここでの教訓は、コードがスケーリングされるにつれて、この新しい機能の噛み付きを感じるということです。

* Stroustrup リファレンスは、C++ 例外処理に関する議論を促進し、潜在的な (必ずしもそうではない) C++ 言語機能を定義するために、ずっと前に書かれました。人間が判読でき、「移植可能」であるため、実装固有のリファレンスよりもこのリファレンスを選択しました。この論文の主な用途はセクション 5 です。具体的には、C++ スタックの巻き戻しの必要性と、そのオーバーヘッドの発生の必要性についての議論です。これらの概念は論文内で正当化されており、現在 C++11 で有効です。

于 2015-10-16T01:52:15.200 に答える