8
#include <iostream>

using namespace std;

struct A
{
    A()
    {
        cout << "A()" << endl;
    }

    ~A()
    {
        cout << "~A()" << endl;
    }

    A(A&&)
    {
        cout << "A(A&&)" << endl;
    }

    A& operator =(A&&)
    {
        cout << "A& operator =(A&&)" << endl;
        return *this;
    }
};

struct B
{
    // According to the C++11, the move ctor/assignment operator
    // should be implicitly declared and defined. The move ctor
    // /assignment operator should implicitly call class A's move
    // ctor/assignment operator to move member a.
    A a;
};

B f()
{
    B b;

    // The compiler knows b is a temporary object, so implicitly 
    // defined move ctor/assignment operator of class B should be
    // called here. Which will cause A's move ctor is called.
    return b; 
}

int main()
{
    f();
    return 0;
}

私の予想される出力は次のようになります。

A()
A(A&&)
~A()
~A()

ただし、実際の出力は次のとおりです: (C++ コンパイラは: Visual Studio 2012)

A()
~A()
~A()

これは VC++ のバグですか? それとも私の誤解ですか?

4

3 に答える 3

14

このブログ投稿によると、VC++ 2012 は現在N2844 + DR1138を実装していますが、 N3053は実装していません。その結果、コンパイラはムーブ コンストラクターまたは代入演算子を暗黙的に生成しません明示的なデフォルトを追加してコンストラクターを移動するとB、期待する出力が得られます。

于 2012-09-28T21:30:24.603 に答える
7

Visual C++ 2012 は、右辺値参照と移動操作に関する最終的な C++11 仕様を実装していません (仕様は標準化プロセス中に数回変更されました)。詳細については、Visual C++ チーム ブログの投稿「Visual C++ 11 の C++11 機能」右辺値参照を参照してください。

具体的には、これは次の 2 つの方法で現れます。

  • ユーザー定義の移動操作の定義はA、暗黙的に宣言されたコピー操作を抑制しません。

  • に対して暗黙的に定義された移動操作はありませんB

于 2012-09-28T21:33:21.983 に答える
1

moveコンストラクタの宣言によってcopy ctorの生成が妨げられることはないと思います。...そして、コンパイラは移動コンストラクターよりもコピーコンストラクターを好むようです。

実際には、12.8 [class.copy] パラグラフ 7 によると、移動コンストラクターの存在はコピー コンストラクターを防止する必要があります。

クラス定義でコピー コンストラクターが明示的に宣言されていない場合は、暗黙的に宣言されます。クラス定義でムーブ コンストラクターまたはムーブ代入演算子が宣言されている場合、暗黙的に宣言されたコピー コンストラクターは削除済みとして定義されます。それ以外の場合は、デフォルト (8.4) として定義されます。

ただし、移動構築の詳細はプロセスの後半まで変更されており、VC++ は実際の標準ではなく、以前のリビジョンを実装しているようです。

于 2012-09-28T21:23:35.383 に答える