4

以下のコードは、関数で作成されたオブジェクトの有効期間が で作成されたオブジェクトの有効期間に延長create()されることを示していますが、これはすべての場合で正しいですか? 一時的な参照を作成することで、特定の場合に一時的な寿命を延ばすことができるということですか? または、この特定のケースでは、コンパイラは誤動作していますか?const refmain

MSVC2005でコンパイルされています

#include <iostream>

class testClass
{
public:
    testClass()
    {
        std::cout << "in testClass " << ((void*)this) << std::endl;
    }

    ~testClass()
    {
        std::cout << "in ~testClass " << ((void*)this) << std::endl;
    }
};


testClass create()
{
    return testClass();
}


int main()
{
    {
        testClass const& obj = create();

        std::cout << "we got a const reference to obj " << ((void*)&obj) << std::endl;
    }

    return 0;
}

出力

in testClass 0018FF13
we got a const reference to obj 0018FF13
in ~testClass 0018FF13

もちろん、他のアドレスは異なる場合があります...上記の場合、関数create()で作成されたオブジェクトのデストラクタを期待していましたが、行の前に呼び出されます

std::cout << "we got a const reference to obj " << ((void*)&obj) << std::endl; 

実行されます。

4

3 に答える 3

6

これは特殊なケースです。const 参照を一時オブジェクトにバインドする、その const 参照がスコープ外になるまでその有効期間が延長されます。これは、関数のローカル const 参照にのみ当てはまります。たとえば、次は機能しません。

struct X
{
  int const& i
  X(int const& i_) : i(i_) {}
};

int f();

int main()
{
  X x(f()); 
  int u = x.i; //!
}

の構築中xi_は によって返されるテンポラリにバインドさfれますiが、これは const 参照ですが、そのテンポラリの寿命は の寿命まで引き伸ばされませんi。つまり、ルールはここで適用されます。

このGOTWの記事を参照してください

更新:記事とコメントで言及されているように、const重要です。C++ 標準では、const 左辺値参照と右辺値参照への一時的なバインドのみが許可されているため、int& i = f();許可されていません。ただし、MSVC にはこれを可能にする拡張機能があり、他の参照と同様に、参照が範囲外になるまで一時的な有効期間が延長されます。コードが移植できなくなるため、その拡張機能を悪用することはお勧めしません。実際、この機能はあまり知られていないため、参照への一時的なバインドには注意が必要です。この機能が機能していることに同僚が困惑する可能性があるため、コードが読みにくくなります。

于 2013-04-17T07:57:56.790 に答える
2

明確にするために、次の 3 つのシナリオを示すことができますtestClass create()

1

コピーを返しますが、const 参照でキャッチします

testClass create()
{
    return testClass();
}

testClass const &obj = create();

一時的な寿命を延長しtestClass()ますobj

 

2

コピーを返し、割り当てによってキャッチする (RVO)

testClass create()
{
    return testClass();
}

testClass obj = create();

RVO が暗黙的に適用されるため、temporary の有効期間が のtestClass()限り延長されます。obj実際、ここには一時的なオブジェクトはなく、すべてのものは関数内でobjも動作しcreate()ます。

 

3

コピーを返し、割り当てによってキャッチする (RVO なし)

testClass create()
{
    return testClass();
}

testClass obj = create();

testClass()から戻った後、temporary の寿命が過ぎcreate()て、新しいオブジェクトが世界にやってきます。

于 2013-04-17T08:08:24.927 に答える
1

このリンクは、この状況がどのように認定されるかを理解するのに役立ちます。

参照変数を初期化するために一時オブジェクトが作成される場合、一時オブジェクトの名前は参照変数と同じスコープを持ちます。完全な式 (別の式の部分式ではない式) の評価中に一時オブジェクトが作成されると、それが作成されたポイントを字句的に含む評価の最後のステップとして破棄されます。

完全式の破棄には 2 つの例外があります。

  • 式は、オブジェクトを定義する宣言の初期化子として表示されます。一時オブジェクトは、初期化が完了すると破棄されます。
  • 参照は一時オブジェクトにバインドされます。一時オブジェクトは、参照の存続期間の終わりに破棄されます。
于 2013-04-17T07:57:01.457 に答える