9

私は右辺値参照についてもっと知りたいと思っていますが、この最も単純な例に行き詰まりました:

#include <iostream>
using namespace std;

struct C {
    C() { cout << "C()\n"; }
    ~C() { cout << "~C()\n"; }
    C(const C&) { cout << "C(const C&)\n"; }
    C& operator=(const C&) { cout << "operator=(const C&)\n"; return *this; }

    C(C&&) { cout << "C(C&&)\n"; }
    C& operator=(C&&) { cout << "operator=(C&&)\n"; return *this; }
};

C foo() { C c; return c; }

int main()
{
    const C c = foo();
    return 0;
}

私はそれをClang 3.2でコンパイルし、-std=c++11 -fno-elide-constructors((N)RVOを避けるために)コンパイルしましたが、結果は私にとって驚くべきものです:

C()
~C()    // huh?
C(C&&)
~C()
~C()

最初の を除いて、まさにそれを期待していました~C()。2 つの構築と 3 つの破壊があるため、それはどこから来たのか、何が欠けているのでしょうか? && コンストラクターは、破棄されたオブジェクト参照で呼び出されていますか??

4

1 に答える 1

3

これはバグに違いありません。で構築されたローカル オブジェクトのデストラクタfoo()が、受信オブジェクトの移動コンストラクタの前に呼び出されています。特に、一時的に割り当てられているようですが、値によって返されるときに (移動) 構築されていないようです。次のプログラムはこれを示しています。

#include <iostream>
using namespace std;

struct C 
{
    C(int z) { id = z; cout << "C():" << id << endl; }
    ~C() { cout << "~C():" << id << endl; }
    C(const C& c) { id = c.id + 1; cout << "C(const C&):" << id << endl; }
    C& operator=(const C&) { cout << "operator=(const C&)\n"; return *this; }
    C(C&& c) { id = c.id + 1; cout << "C(C&&):" << id << endl;}
    C& operator=(C&&) { cout << "operator=(C&&)\n"; return *this; }
    int id;
};

C foo() { C c(10); return c; }

int main()
{
    const C c = foo();
    return 0;
}

出力:

C():10
// THE TEMPORARY OBJECT IS PROBABLY ALLOCATED BUT *NOT CONSTRUCTED* HERE...
~C():10 // DESTRUCTOR CALLED BEFORE ANY OTHER OBJECT IS CONSTRUCTED!
C(C&&):4198993
~C():4198992
~C():4198993

の中に2 つのオブジェクトを作成するfoo()と、問題がさらに明らかになるようです。

C foo() { C c(10); C d(14); return c; }

出力:

C():10
C():14
~C():14
// HERE, THE CONSTRUCTOR OF THE TEMPORARY SHOULD BE INVOKED!
~C():10
C(C&&):1 // THE OBJECT IN main() IS CONSTRUCTED FROM A NON-CONSTRUCTED TEMPORARY
~C():0 // THE NON-CONSTRUCTED TEMPORARY IS BEING DESTROYED HERE
~C():1

興味深いことに、これは でのオブジェクトの構築方法に依存しているようfoo()です。foo()このように書かれている場合:

C foo() { C c(10); return c; } 

その後、エラーが表示されます。このように書かれている場合、次のことはありません。

C foo() { return C(10); }

のこの最後の定義による出力foo():

C():10 // CONSTRUCTION OF LOCAL OBJECT
C(C&&):11 // CONSTRUCTION OF TEMPORARY
~C():10 // DESTRUCTION OF LOCAL OBJECT
C(C&&):12 // CONSTRUCTION OF RECEIVING OBJECT
~C():11 // DESTRUCTION OF TEMPORARY
~C():12 // DESTRUCTION OF RECEIVING OBJECT
于 2013-01-12T21:25:57.920 に答える