13

小さなコード スニペットを次に示します。

class A
{
public:
    A(int value) : value_(value)
    {
        cout <<"Regular constructor" <<endl;
    }

    A(const A& other)   : value_(other.value_)  
    {
        cout <<"Copy constructor" <<endl;
    }

private:
    int value_;
};
int main()
{
    A a = A(5);
}

出力は「通常のコンストラクター」(RHS の場合) に続いて、LHS の「コピー コンストラクター」になると想定しました。だから私はこのスタイルを避け、常にクラスの変数を として宣言しましA a(5);た。しかし、上記のコードで驚いたことに、コピー コンストラクターは呼び出されません (Visual C++ 2008)

この動作がコンパイラの最適化の結果なのか、それとも C++ の文書化された (および移植可能な) 機能の結果なのか、誰にもわかりませんか? ありがとう。

4

4 に答える 4

15

別のコメントから:「デフォルトでは、それに依存するべきではありません(コンパイラに依存する可能性があるため)」

いいえ、実際にはコンパイラに依存しません。砂粒の価値があるコンパイラは、A を作成してからコピーするのに時間を無駄にしません。

標準では、T = x;が と同等であることは完全に許容されると明示的に述べていますT(x);。(§12.8.15, pg. 211) でこれを行うのT(T(x))は明らかに冗長であるため、内部の を削除しTます。

目的の動作を得るには、コンパイラに最初の A をデフォルトで構築させる必要があります。

A a;
// A is now a fully constructed object,
// so it can't call constructors again:
a = A(5);
于 2009-11-18T18:53:02.790 に答える
7

だまされて閉じられた別の質問に答えるためにこれを調査していたので、作業を無駄にしないために、代わりにこれに答えています。

形式のステートメントは、変数のコピー初期化A a = A(5)と呼ばれます。C++11 標準、8.5/16 には次のように記載されています。a

選択された関数は、初期化式を引数として呼び出されます。関数がコンストラクターの場合、呼び出しは、目的の型の cv 修飾されていないバージョンの一時を初期化します。一時的なものは prvalue です。呼び出しの結果 (コンストラクターの場合は一時的なもの) は、上記の規則に従って、コピー初期化の宛先であるオブジェクトを直接初期化するために使用されます。場合によっては、中間結果を初期化されるオブジェクトに直接構築することにより、この直接初期化に固有のコピーを排除する実装が許可されます。12.2、12.8を参照

これは、コンパイラが適切なコンストラクタを検索して を処理A(5)し、一時を作成して、その一時を にコピーすることを意味しaます。しかし、どのような状況でコピーを排除できるのでしょうか?

12.8/31 の内容を見てみましょう:

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

[...]

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

これらすべてを念頭に置いて、式で何が起こるかを次に示しますA a = A(5)

  1. コンパイラは、コピー初期化を伴う宣言を認識します
  2. コンストラクターは、A(int)一時オブジェクトを初期化するために選択されています
  3. 一時オブジェクトは参照にバインドされておらずA、コピー初期化式の目的の型と同じ型を持っているため、コンパイラはオブジェクトを に直接構築しa、一時オブジェクトを省略できます。
于 2012-03-30T15:06:03.100 に答える
4

ここでは、from temporaryのコピー初期化があります。実装では、C++ 標準 12.2/2 に従って、ここでコピー コンストラクターの呼び出しをスキップできます。aA(5)

于 2009-11-18T19:54:19.203 に答える
-1
A a = A(5);

この行は次と同等です

A a(5);

関数スタイルの外観にもかかわらず、最初の行は単純aに引数 5 で構成されています。コピーや一時変数は含まれていません。C++ 標準のセクション 12.1.11 から:

関数表記の型変換 (5.2.3) を使用して、その型の新しいオブジェクトを作成できます。[ 注: 構文は、コンストラクターの明示的な呼び出しのように見えます。—終わりのメモ]

于 2009-11-19T17:46:09.027 に答える