2013-03-12 9 views
13

私は、コンストラクタと代入演算がC++ 11で動作する方法を理解しようとしていますが、親クラスへの委譲に問題があります。コンストラクタと継承を移動する

コード:しかし

class T0 
{ 
public: 
    T0() { puts("ctor 0"); } 
    ~T0() { puts("dtor 0"); } 
    T0(T0 const&) { puts("copy 0"); } 
    T0(T0&&) { puts("move 0"); } 
    T0& operator=(T0 const&) { puts("assign 0"); return *this; } 
    T0& operator=(T0&&) { puts("move assign 0"); return *this; } 
}; 

class T : public T0 
{ 
public: 
    T(): T0() { puts("ctor"); } 
    ~T() { puts("dtor"); } 
    T(T const& o): T0(o) { puts("copy"); } 
    T(T&& o): T0(o) { puts("move"); } 
    T& operator=(T const& o) { puts("assign"); return static_cast<T&>(T0::operator=(o)); } 
    T& operator=(T&& o) { puts("move assign"); return static_cast<T&>(T0::operator=(o)); } 
}; 

int main() 
{ 
    T t = std::move(T()); 
    return 0; 
} 

、私はコンパイルしてVS2012の下で実行し、出力はT0メンバーの左辺値のバージョンが呼ばれていることを示しています

ctor 0 
ctor 
copy 0 <-- 
move <-- 
dtor 
dtor 0 
dtor 
dtor 0 

似たような状況を(とわずかに異なるテストケース)が移動割り当てで発生します.Tの移動代入演算子は、T0の「通常の」代入演算子を呼び出します。

私は間違っていますか?

答えて

16

ワン右辺値参照をパラメータとして取る関数についての混乱は、内部的にそれらの値を左辺値として扱うことです。これは、あなたが意味する前にパラメータを移動させないようにするためですが、慣れるまでに時間がかかります。実際にパラメータを移動するには、std :: move(またはstd :: forward)を呼び出す必要があります。だから、あなたの移動のコンストラクタを定義する必要がありますよう:

T(T&& o): T0(std::move(o)) { puts("move"); } 

と、あなたの移動代入演算子:

T& operator=(T&& o) { puts("move assign"); return static_cast<T&>(T0::operator=(std::move(o))); } 
5

あなたは今まで左辺値を使用して基本クラスのものを呼び出している:ある

void foo(int&){} // A 
void foo(int&&){} // B 

void example(int&& x) 
{ 
    // while the caller had to use an rvalue expression to pass a value for x, 
    // since x now has a name in here it's an lvalue: 
    foo(x); // calls variant A 
} 

example(std::move(myinteger)); // rvalue for us, lvalue for example 

は、次のものが必要です。

T(T&& o): 
T0(std::move(o)) // rvalue derived converts to rvalue base 
{ 
    puts("move"); 
} 

そして:より多くの

T& operator=(T&& o) 
{ 
    puts("move assign"); 

    T0::operator=(std::move(o))); 

    return *this; 
} 
関連する問題