0

VC++2012 を使用して次のコードを実行しています。

#include <utility>

struct A
{
    int* m_p;

    A() { m_p = new int; }
    ~A() { delete m_p;  }

    A(const A& otherA)
    {
        m_p = new int;

        // BOOM!
        *m_p = *otherA.m_p;
    }
};

A&& CreateA()
{
    A a;
    return std::move(a);
}

int _tmain(int argc, _TCHAR* argv[])
{
    A a2 = CreateA();
    return 0;
}

a2 の作成中に、CreateA() で作成されたソース オブジェクトが既に破棄されているため、A のコピー ctor が呼び出されてクラッシュします。これは標準的な動作ですか?これはコンパイラのバグでしょうか??

a2 の型を 'A' から 'const A&' に変更すると、クラッシュが発生しないことに注意してください。これは、実際にバグであるという疑いを強めます。誰でもこれに光を当てることができますか?

注: これが右辺値参照の意図された使用法ではないことは十分承知しており、この例は不自然です。この新しいタイプの動作をよりよく把握できることを願っています。

4

2 に答える 2

2

コードで何が起こるかを見てください。

  1. CreateA()と呼ばれる
  2. 関数内で、タイプのローカル変数Aが作成されます。
  3. このローカル変数を指す右辺値参照を作成します
  4. この右辺値参照を返します
  5. A戻ると、右辺値参照が指すtype のオブジェクトがスコープ外になり、破棄されます
  6. 参照は破壊されたオブジェクトを指すようになりました
  7. 関数呼び出し内にかつてa2存在していたオブジェクトのコピーとして初期化しようとしています

そして...それはうまくいきません。コピーしようとしているオブジェクトは死んでしまいました。未定義の動作。

そうしないでください。:)

C++ では、参照は参照先オブジェクトの存続期間に影響しません。「この物体を指しているから破壊できない!」ということはありません。

ローカル オブジェクトへの参照を返さないでください。うまくいかないので... やらないでください。

于 2012-12-21T16:31:53.020 に答える
2

スコープ外のローカル変数にはアクセスできません。右辺値参照はそれを変更しません: それらはまだ参照です。提示されたコードは、ローカル変数への参照を返し、それにアクセスするため、未定義の動作をします。

右辺値参照を返さないでください。それはほとんどの場合ばかげています。代わりに値を返します。

A CreateA()
{
    A a;
    return a; // a move here is automatic
              // unless you are using a compiler with outdated rules like MSVC
    //return std::move(a); // ok, poor MSVC
    // alternatively:
    //return A{}; //or 
    //return A();
}

A const& a2 = CreateA();実際にはオブジェクトにアクセスしないため、何も記述しないとクラッシュしません。あなたがすることは、ぶら下がっている参照をつかむことだけです。ただし、このコードは整形式ではありません。MSVC には参照バインディングに関する古い規則がいくつかあるため、たまたまコンパイルされるだけです。

したがって、基本的に、これらの動作はコンパイラのバグと未定義の動作が混在しています:)

于 2012-12-21T16:18:53.663 に答える