3
#include <iostream>

class Class
{
    public:
    Class() { std::cerr << "ctor" << std::endl; }
    ~Class() { std::cerr <<"dtor" << std::endl; }

    Class(Class&)  { std::cerr << "copy ctor" << std::endl; }
    Class & operator=(const Class &)
    {
            std::cerr << "copy operator=" << std::endl;
            return *this;
    }

    Class(Class&&) { std::cerr << "move ctor" << std::endl;}
    Class & operator=(Class &&)
    {       
            std::cerr << "move operator="<< std::endl;
            return *this;
    }
 };

int main(int, char**)
{
    Class object;
    Class && rvr = Class(); 
    object = rvr; // (*)
}

出力は

ctor
ctor
copy operator=
dtor
dtor

1) 行 (*) で「copy ctor」が呼び出されるのはなぜですか?

2)毎回 std::move() を使用する必要がある場合、「移動セマンティクス」とデータを移動するメソッドの違いは何object.destructive_move();ですか?

3) 正確に move ctor/operator が呼び出されるのはいつですか?

ありがとう!

4

2 に答える 2

7

コピー ctor は行 (*) で呼び出されず、コピー代入演算子が呼び出されます。それがあなたの意図したことだと思います。

rvrは左辺値であるため、移動代入演算子ではなく、コピー代入演算子が呼び出されます。式の型は、左辺値であるかどうかに直交することに注意してください。

代入ステートメントをobject = Class();またはに変更した場合object = static_cast<Class&&>(rvr)、移動代入演算子が呼び出されていることがわかります。これは、これら 2 つのケースでは RHS が右辺値であるためです。

この動作は理にかなっています。たとえば、移動代入演算子の実装を考えてみてください。そのパラメーターには右辺値参照型がありますが、左辺値のままです。右辺値の場合、パラメーターを最初に使用すると、その状態が変更されて「空の」オブジェクトになり (移動セマンティクス)、パラメーターを 2 回目に使用すると、期待どおりに機能しない可能性があります。

それが実際に機能std::moveする方法は、「空の」状態のままにする方法でパラメーターを使用したい場合に明示的に使用します。

于 2012-07-01T17:07:35.760 に答える
3
Class && rvr = Class(); 

私が言おうとしていることに意味はありませんが、これが C++11 のルールです。

rvrへの右辺値参照である変数ですClass。それは簡単に理解できます。ただし、これを理解することが重要です。名前付き変数は決して右辺値式ではありません。右辺値参照であっても!

繰り返しますが、意味がないことはわかっていますが、それがルールです。右辺値参照変数は右辺値式ではありません

一時的なものは右辺値式であるため、Class()右辺値が得られます。関数から返される一時的なものも右辺値式であるため、値によって返される関数がある場合はClass、右辺値が返されます。

左辺値参照と右辺値参照 (コピー/移動コンストラクター/代入など) に基づいてオーバーロードされた 2 つの関数がある場合、C++11 は式の型が右辺値である場合にのみ右辺値参照バージョンを選択するため、これは重要です。

std::moveこれが存在する理由です。何かを動かしたいときに明示的に述べるために存在します。これは、与えられた値を右辺値式に変換することによって行われます。つまり、 を返しますClass&&

これは本当に混乱する部分です。名前付きの右辺値参照変数がある場合、それは右辺値式ではありません。ただし、関数から戻るなど、名前のない右辺値参照がある場合、それは右辺値式です。Class&&

std::move戻りますClass&&。したがって、名前付き変数から移動したい場合は、常にそれを呼び出す必要がありますstd::move。したがって、 から移動する場合はrvr、次のようにする必要があります。

object = std::move(rvr); // (*)

Class&&これは aをに返しrvrます。C++11 のオーバーロードの解決が行われます。パラメータ tooperator=は右辺値式であるため、 の右辺値参照バージョンが選択されますoperator=。したがって、移動を呼び出します。

std::moveは、半複雑なキャストのラッパーにすぎないことに注意してください。移動はしません。移動を行うのoperator=は です。

于 2012-07-01T20:00:14.007 に答える