0

通常のコンストラクターとコピーコンストラクターを含むクラスを使用した次の単純なコードがあります

class largeObj
{
public:
    largeObj()
    {
        printf("\nNormal constructor\n");
    }

    largeObj(const largeObj& mv)
    {
        printf("\nCopy constructor\n");
    }

    ~largeObj()
    {
        printf("\nDestroying..\n");
    }

    void tryme()
    {
        printf("\nHi :)\n");
    }

};

largeObj iReturnLargeObjects()
{
    largeObj md;


    return md;
}


int main()
{

    largeObj mdd = iReturnLargeObjects();

    mdd.tryme();

    return 0;
}

出力は

通常のコンストラクタ

コンストラクターのコピー

破壊..

こんにちは :)

そして、私はその理由を理解しました。

しかし、次の行を置き換えると

largeObj mdd = iReturnLargeObjects();

largeObj& mdd = iReturnLargeObjects();

出力は同じですが、それはなぜですか?

つまり、最初のケース (& なし) に別のコピーがあるべきではありませんか? これら 2 つの行の違いは何ですか? また、なぜ同じように動作するのですか?

4

2 に答える 2

4
largeObj& mdd = iReturnLargeObjects();

変更可能な左辺値参照を右辺値にバインドすることはできません。これは違法な C++ であり、一部の特定のコンパイラ拡張でのみ許可されています。constただし、この参照が有効であり、割り当てが有効であったとしても、質問のセマンティクスは変更されません。

出力が変わらない理由は、RVO と呼ばれるコンパイラの最適化のためです。C++ 標準で明示的に許可されているこの最適化により、コンパイラは、特定の制限内で不要であると判断したオブジェクトの構築をスキップできます。これにより、プログラムのセマンティクスが変更されるため、非常に珍しい最適化になります。

肝心なのは、コピー/移動コンストラクターとデストラクタに副作用を入れないでください。プログラムの正確性がそれらが呼び出されることに依存している場合でも、コンパイラはそれらを排除できるからです。

于 2012-04-10T22:35:40.583 に答える
0

どのコンパイラを使用しましたか。どのコンパイラを使用しても、リターン後に未使用のスタック変数がゼロにならなかったため、これがうまくいったと確信しています。基本的に md はスタックに残されましたが、技術的にはまだ対処できます。両者の違いは

largeObj md;

変数全体を受け取る変数です。

largeObj& mdd = iReturnLargeObjects();

怠惰なコンパイラのためにまだ存在する変数への参照です。

于 2012-04-10T23:00:22.500 に答える