5

RVO (および NRVO) の定義について理解できません。これは、RVO がコピー コンストラクターを省略していると仮定して、このような質問が複数あるためです。12.8.15によると

このような場合、実装は、省略されたコピー操作のソースとターゲットを、同じオブジェクトを参照する 2 つの異なる方法として扱い、そのオブジェクトの破棄は、2 つのオブジェクトが削除されなかった場合に発生します。最適化。

コピー コンストラクターの呼び出しが省略されているのではなく、コピー自体が省略されているように見えます。最初にオブジェクトが「コピー」の場所に構築されるだけなので、「元の」オブジェクトはなく、コピーもまったくありません。したがって、クラスにprivateコピー コンストラクターがある場合でも、コピーがないため、RVO が開始されたときに関数から返される可能性があります。

私はそれを正しく理解していますか?コピー自体が省略されているか、コピーコンストラクタの呼び出しが省略されていますか? オブジェクト クラスにプライベート コピー コンストラクターがある場合、関数からオブジェクトを返すことを許可する必要がありますか?

4

6 に答える 6

8

最適化が有効になった場合、コピーは省略されますが、コピー コンストラクターにアクセスできることを確認するためにコンパイラは引き続き必要です。そうしないと、コンパイラ (または他のコンパイラ) が最適化しないことを決定した場合に、コードが無効になります。

于 2012-04-24T06:31:59.553 に答える
7

コピー自体が省略されているか、コピーコンストラクタの呼び出しが省略されていますか?

コピー操作自体は省略します。引用全体を見ると、次のように明確に述べられています。

C++ 03 12.8 クラス オブジェクトのコピー

パラ15

特定の基準が満たされると、オブジェクトのコピー コンストラクターやデストラクタに副作用がある場合でも、実装はクラス オブジェクトのコピー構築を省略できます。そのような場合、実装は、省略されたコピー操作のソースとターゲットを、同じオブジェクトを参照する単純な 2 つの異なる方法として扱い、そのオブジェクトの破棄は、2 つのオブジェクトが削除された時点のうちの遅い方の時点で発生します。 111) このコピー操作の省略は、次の状況で許可されます (複数のコピーを排除するために組み合わせることができます)。

— クラスの戻り値の型を持つ関数の return ステートメントで、式が関数の戻り値の型と同じ cv-unqualified 型を持つ不揮発性の自動オブジェクトの名前である場合、コピー操作は自動オブジェクトを構築することによって省略できます。オブジェクトを関数の戻り値に直接代入します。

— 参照 (12.2) にバインドされていない一時クラス オブジェクトが、同じ cv 修飾されていない型のクラス オブジェクトにコピーされる場合、一時オブジェクトを省略されたオブジェクトのターゲットに直接構築することによって、コピー操作を省略できます。コピー.....

オブジェクト クラスにプライベート コピー コンストラクターがある場合、関数からオブジェクトを返すことを許可する必要がありますか?

RVO と NRVO はコンパイラの最適化であり、コンパイラによって許可されていますが、保証されていません特定の愚かなコンパイラがこれらの最適化を提供できない場合はどうなりますか?
アクセス可能なコピー コンストラクターがないと、そのようなすべてのコンパイラーでコードが壊れてしまい、望ましくありません。コピーコンストラクターにアクセスできる必要があるとします。

于 2012-04-24T06:35:01.550 に答える
3

公式には、いいえ、RVO/NRVO は、プログラムが適切に形成されているかどうかには影響しません。標準では、コピー コンストラクターからの副作用を省略することを明示的に許可しています、コピー コンストラクターに対するアクセス チェックは引き続き実行する必要があります。

ただし、ほとんどのコンパイラは、ルールをできるだけ厳密に適用するように要求しない限り、省略されたコピー コンストラクターのアクセス チェックを行いません。確実ではありませんが、厳密なコンプライアンスを要求した場合でも、アクセス チェックをスキップしたものをいくつか使用したことを覚えているようです (確かなことは覚えていません)。

編集(他の回答のいくつかで表現されている誤解として私が見ているものを修正するため):

規格のセクション内の段落は、順番に読むことを意図しています。状況に適用される最初の段落の要件は常に適用されます。この場合、副作用を省略する許可は段落 15 にあります。ただし、その直前の段落 14 では、次のことがわかります。

オブジェクトのコピーコンストラクターまたはコピー代入演算子が暗黙的に使用され、特別なメンバー関数にアクセスできない場合、プログラムは不正な形式です (節 11)。

したがって、段落 14 で指定されたアクセス チェックが既にパスされている場合にのみ、段落 15 (コピーを省略できます) に到達します。

于 2012-04-24T06:35:52.453 に答える
2

省略されるのはコピーそのものです。コピーが実際に行われるときはいつでも、コピー コンストラクターを使用して行う必要がありますが、コンパイラがコピーを最適化して削除できる場合がいくつかあります。

より大きく、Pod 以外のオブジェクトは、スタックによって返されます。呼び出し元は、オブジェクトのスペースを準備し、そのスペースへのポインターを隠しパラメーターとして渡します。呼び出し先は、オブジェクトをそのスペースにコピーします。ここでは、2 つの最適化を行うことができます。

  1. 呼び出し先は、戻り空間で直接オブジェクトを作成できます。コンパイラは、オブジェクトが返されることを確認する必要があります。つまり、そのオブジェクトを返す return ステートメントのみが続き、介在するコードがスローされてはなりません。
  2. 結果が変数に割り当てられている場合、呼び出し元は一時変数を作成する代わりにそのアドレスを渡すことができます。これは、変数が初期化されている場合、または効果が の呼び出しと変わらないことが証明されている場合にのみ実行できますoperator=。これは、基本的に、型にデフォルトのコンストラクタ、デストラクタ、および がある場合ですoperator=
于 2012-04-24T06:41:40.513 に答える
1

コピー自体が省略されているか、コピーコンストラクタの呼び出しが省略されていますか?

プログラムのセマンティクスを変更しない限り、コンパイラはメモリを共有できますが、コピー コンストラクタは省略されます。

オブジェクト クラスにプライベート コピー コンストラクターがある場合、関数からオブジェクトを返すことを許可する必要がありますか?

いいえ、許可されていません。「そうすべきか」と言うのは難しいですが、それを許可すると、あらゆる種類の悪ふざけを実行してカプセル化を破ることができます。C++11 では{}、return で構築を使用し、その値を構築して move することで、これを行うことができます。

于 2012-04-24T06:34:57.303 に答える
0

この記事を見ると、MSDN で明らかになった NRVO

コピー コンストラクターが呼び出されていないことがわかります。

于 2012-04-24T06:31:43.533 に答える