17

このプログラムの場合

#include <iostream>
using std::cout;

struct C 
{
    C() { cout << "Default C called!\n"; }
    C(const C &rhs) { cout << "CC called!\n"; }
};

const C f()
{
    cout << "Entered f()!\n";
    return C();
}

int main()
{
    C a = f();
    C b = a;

    return 0;
}

私が得る出力は次のとおりです。

Entered f()!
Default C called!
CC called!

f()は値で返されるため、一時的なものを返す必要があります。のようT a = x;に、一時的に渡されたものを引数として、T a(x);の構築のためにコピーコンストラクターを呼び出しませんか?a

4

3 に答える 3

14

f()は値で返されるため、一時的なものを返す必要があります。のようT a = x;に、一時的に渡されたものを引数として、T a(x);の構築のためにコピーコンストラクターを呼び出しませんか?a

戻り値の最適化を検索します。これはデフォルトでオンになっています。MSVC 2005+を使用しているWindowsを使用している場合は、/Odこれをオフにして、目的の結果(または-fno-elide-constructorsGCC)を取得するために使用できます。また、MSVCについては、この記事を参照してください。

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

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

クラスreturn型の関数のreturnステートメントで、 式が関数return型と同じcv-unqualified型の不揮発性自動オブジェクトの名前である場合、自動を構築することでコピー操作を省略できます。オブジェクトを関数の戻り値に直接— throw-expressionで、オペランドが非揮発性の自動オブジェクトの名前である場合、自動オブジェクトを直接作成することにより、オペランドから例外オブジェクト(15.1)へのコピー操作を省略できます。例外オブジェクトに

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

—例外ハンドラの例外宣言(15節)が例外オブジェクト(15.1)と同じタイプのオブジェクト(cv-qualificationを除く)を宣言する場合、例外宣言を例外宣言によって宣言されたオブジェクトのコンストラクタとデストラクタの実行を除いて、プログラムの意味が変更されない場合は、例外オブジェクトのエイリアス。

注:強調鉱山

于 2010-02-24T02:19:57.550 に答える
4

これは、コンパイラがサポートする戻り値最適化(RVO)機能の例です。

値で返すときに、コピーコンストラクターが呼び出されない場合があります。

GCCのオプションを使用-fno-elide-constructorsして、その機能をオフにします。

于 2010-02-24T02:18:54.053 に答える
2

それは戻り値の最適化と呼ばれていると思います。

f()オブジェクトを返すCとき、オブジェクトは呼び出し元のメソッドのスタックスペースに割り当てられるため、初期化するためにコピーは必要ないと思いますC a。これはあなたdefault C calledです。

C b = a

これにより、コピーコンストラクタが発生しますCC called

ところで、ウィキの例はあなたのコードに非常に似ています。

于 2010-02-24T02:24:58.643 に答える