4

move-constructor が呼び出されないことがあるのはなぜですか? 移動セマンティクスのテスト(ライブ コード) :

struct Test {
    int id;
    Test(int id) : id(id) {
        cout << id << "  Test() " << endl;
    }
    ~Test() {
        cout << id << "  ~Test() " << endl;
    }
    Test(const Test &t) : id(t.id) {
        cout << id << "  Test(const Test &t) " << endl;
    }
    Test(Test &&t) : id(t.id) {
        cout << id << "  Test(Test &&t) " << endl;
    }
    Test &operator=(const Test &t) {
        cout << id << "  operator=(const Test &t) " << endl;
        return *this;
    }
    Test &operator=(Test &&t) {
        cout << id << "  operator=(Test &&t) " << endl;
        return *this;
    }
};

void f(Test z) {
    cout << z.id << "  f(Test z) " << endl;
}

int main() {
    f(Test(1));

    Test t(2); f(t);
}

出力:

1  Test() 
1  f(Test t)               <---// where is move constructor ?!
1  ~Test() 
2  Test() 
2  Test(const Test &t)     <---// copy constructor of t(2)
2  f(Test t) 
2  ~Test() 
2  ~Test()

テストは、コピー コンストラクターが呼び出されることを示しています。

しかし、の右辺値オブジェクトに対して move-constructor を呼び出さずにf(Test(1));関数が呼び出された後。fTest(1)

それは暗黙のコンパイラ最適化ですか? または私は重要な点を逃しましたか?

4

1 に答える 1

8

コンパイラは、一時オブジェクトのコピー (または移動) を除外することを明示的に許可されています。基本的に効果が期待できる場所にオブジェクトを構築します。この省略は、コンストラクタまたはデストラクタに副作用がある場合でも許可されます。

関連する条項は、12.8 [class.copy] パラグラフ 31 です。

特定の基準が満たされると、コピー/移動操作用に選択されたコンストラクターおよび/またはオブジェクトのデストラクタに副作用がある場合でも、実装はクラス オブジェクトのコピー/移動構築を省略できます。このような場合、実装は、省略されたコピー/移動操作のソースとターゲットを、同じオブジェクトを参照する 2 つの異なる方法として扱い、そのオブジェクトの破棄は、2 つのオブジェクトが削除されていた時間のうちの遅い方の時点で発生します。最適化なしで破壊されました。コピー省略と呼ばれるこのコピー/移動操作の省略は、次の状況で許可されます (複数のコピーを排除するために組み合わせることができます): ...

コピー省略が使えるケースは基本的に

  1. return一時変数またはローカル変数を返すときのステートメント内。
  2. throw一時変数またはローカル変数をスローするときの式。
  3. 一時オブジェクトがコピーされるとき。
  4. オブジェクトを値でキャッチする場合。

コピーを省略できる正確な条件は、12.8 [class.copy] パラグラフ 31 に記載されています。

コピー/移動の省略を防ぐ最も簡単な方法は、適切な参照を返す関数を介して渡すことです。

f(std::move(Test(1)));

移動の省略を防ぐ必要があります。

于 2013-10-03T21:21:50.710 に答える