const ref undefined behaviorによって新しく構築されたオブジェクトをキャプチャしています


11

次の(不自然な例)は大丈夫ですか、それとも未定義の動作ですか?

// undefined behavior?
const auto& c = SomeClass{};

// use c in code later
const auto& v = c.GetSomeVariable();

回答:


12

安全。const refは、temporaryの寿命を延ばします。スコープはconst refのスコープになります。

一時オブジェクトの存続期間は、const左辺値参照または右辺値参照(C ++ 11以降)にバインドすることによって延長できます。詳細については、 参照の初期化を参照してください。

参照が一時オブジェクトまたはそのサブオブジェクトにバインドされている場合は常に、一時オブジェクトの存続期間が延長され、参照の存続期間と一致しますが、次の例外があります

  • returnステートメント内の関数の戻り値に一時的にバインドされているものは拡張されません。戻り式の終わりですぐに破棄されます。このような関数は常にダングリングリファレンスを返します。
  • コンストラクター初期化子リストの参照メンバーに一時的にバインドされるのは、オブジェクトが存在する限りではなく、コンストラクターが終了するまで持続します。(注:このような初期化はDR 1696の時点で正しくありません)。
  • 関数呼び出しの参照パラメーターに一時的にバインドされたものは、その関数呼び出しを含む完全な式が終了するまで存在します。関数が完全な式よりも長い参照を返す場合、それはぶら下がり参照になります。
  • new-expressionで使用されるイニシャライザの参照への一時的なバインドは、初期化されたオブジェクトではなく、そのnew-expressionを含む完全な式の終わりまで存在します。初期化されたオブジェクトが完全な式よりも長く存続する場合、その参照メンバーはぶら下がり参照になります。
  • 初期化子を含む完全な式の終わりまで、リスト初期化構文(中括弧)とは対照的に、直接初期化構文(括弧)を使用して初期化された集合体の参照要素の参照に一時的にバインドされます。 struct A { int&& r; }; A a1{7}; // OK, lifetime is extended A a2(7); // well-formed, but dangling reference

一般に、一時オブジェクトの寿命は、「それを渡す」ことによってさらに延長することはできません。一時ファイルがバインドされた参照から初期化された2番目の参照は、その寿命に影響を与えません。

@Konradルドルフが指摘(と上記の最後の段落を参照してください):

c.GetSomeVariable()ローカルオブジェクトへの参照またはそれ自体がオブジェクトの存続期間を延長している参照を返す場合、存続期間の延長は開始されません。」


1
その引用の出典を引用する必要があります。
オービットでの軽量レース

@LightnessRaceswithMonica完了しました。もっと良い文章を探していました。
Oblivion

2
これは値にのみ当てはまることを強調しておくとよいでしょう。場合はc.GetSomeVariable()戻り参照それはいくつかのオブジェクトの生存期間を延長し、それ自体であることをローカルオブジェクトまたは参照に、寿命延長がないではないで蹴る。
コンラートルドルフ

@KonradRudolphありがとう!私も例外を追加しました。
Oblivion


3

はい、これは完全に安全です。const参照へのバインディングは、一時的なものの有効期間をその参照のスコープまで延長します。

ただし、動作は推移的ではないことに注意してください。たとえば、

const auto& cc = []{
    const auto& c = SomeClass{};
    return c;
}();

cc ぶら下がり。


2

これは安全です。

[class.temporary]/5:一時完全式の最後とは異なる時点で破棄される3つのコンテキストがあります。[..]

[class.temporary]/6:3番目のコンテキストは、参照が一時オブジェクトにバインドされている場合です。参照がバインドされている一時オブジェクト、または参照がバインドされているサブオブジェクトの完全なオブジェクトである一時オブジェクトは、参照がバインドされいるglvalueが次のいずれかによって取得された場合、参照の存続期間中存続します。 :[ここにたくさんあります]


1

この特定のケースでは安全です。ただし、すべての一時ファイルがconst参照によって安全にキャプチャできるわけではないことに注意してください...たとえば

#include <stdio.h>

struct Foo {
    int member;

    Foo() : member(0) {
        printf("Constructor\n");
    }

    ~Foo() {
        printf("Destructor\n");
    }

    const Foo& method() const {
        return *this;
    }
};

int main() {
    {
        const Foo& x = Foo{};        // safe
        printf("here!\n");
    }
    {
        const int& y = Foo{}.member; // safe too (special rule for this)
        printf("here (2)!\n");
    }
    {
        const Foo& z = Foo{}.method(); // NOT safe
        printf("here (3)!\n");
    }
    return 0;
}

取得された参照zは、printfステートメントに到達する前の完全な式の終わりに一時インスタンスが破棄されるため、安全に使用できません。出力は次のとおりです。

Constructor
here!
Destructor
Constructor
here (2)!
Destructor
Constructor
Destructor
here (3)!
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.