2013-05-17 3 views
9

次のコードでstd :: moveが何か良いことをするのか、それとも完全に間違っているのかわかりません。 クラスObjectには、移動コンストラクタとコピーコンストラクタの両方が定義されています。std :: moveは有効性のためにreturn文で使用する必要がありますか?

まず:移動付:

template<typename T> template <typename F> 
const Object<T> Object<T>::operator*(const F& rhs) const 
{ 
    return std::move(Object(*this) *= rhs); // We end in move constructor 
} 

第二:移動なし:

template<typename T> template <typename F> 
const Object<T> Object<T>::operator*(const F& rhs) const 
{ 
    return Object(*this) *= rhs; // We end in copy constructor 
} 

*=オペレータは次のように定義される:ここでは

template<typename T> template<typename F> 
Object<T>& Object<T>::operator*=(const F& rhs) 
{ 
    for(int i = 0; i < dimension ; i++) 
    { 
     _inner[i] *= rhs; 
    } 
    return *this; 
} 

は共同ですドは、私はそれをテストするために使用します。

Object<double> test(4); 
Object<double> test2(test * 4); 
std::cout << test2; // works fine 

結果、我々は移動コンストラクタで終わる最初場合と 我々はコピーコンストラクタで終わります。

いずれの場合も、コードがコンパイルされます。

新しいオブジェクトをコピーするのではなく移動するほうが速いと思うので、もう1つ効率的ですか?

追加情報: 私は次のコンパイラを使用します。私はそれがあると仮定しますので、G ++(Ubuntuの/リナロ4.7.3-1ubuntu1)4.7.3

+7

'const'値を返さず、' std :: move'ローカル変数/一時変数を明示的に指定しないで、(N)RVOを禁止します。あなたの '演算子*'を 'Object tmp(* this);と書くのはなぜでしょうか。 tmp * = rhs; return tmp; '?こうすることで、コンパイラはローカル変数を返すことを確認し、それを 'return'すると自動的にrvalueに変換します。 – Xeo

+0

を見てください:http://stackoverflow.com/questions/4986673/c11-rvalues-and-move-semantics-confusion – Steve

+0

私は 'const'なしでテストしましたが、状況は変わりませんが、私は理解できました'std :: move'が必要な答えから' lvalue'を返します。一方、それが 'rvalue'だった場合、' std :: move'は必要ありませんでした。最後に、一時変数を使用すると、自動的に移動されますか? – CodeTower

答えて

14

は一方が他方よりは、より効率的です新しいオブジェクトをコピーするのではなく、移動する方が速いのですか?

はい、ここでstd::moveを使用すると、オブジェクトがコピーよりも効率的な移動セマンティクスを持つと仮定すると、より効率的になります。

通常、一時変数またはローカル変数を返すときは、移動セマンティクスが自動的に使用されます。ただし、この場合は一時的に直接返信するのではなく、左端の参照はoperator*=から返されます。 左辺は移動されませんので、この場合はstd::moveが必要です。の右辺値に変更してください。

ただし、constの値を返さないでください。戻り値が別のオブジェクトの移動初期化(または移動割り当て)に使用されないためです。あなたの例では、test2によってが返されます。のコピーは返されますが、そのコピーは省略される可能性があります。

代わりに、ローカル変数を使用して、それを実現することができます。

template<typename T> template <typename F> 
Object<T> Object<T>::operator*(const F& rhs) const 
{ 
    Object lhs(*this); 
    lhs *= rhs; 
    return lhs; 
} 

は、戻り値を移動することができるだけでなく、動き自体は省略させることができます。

+0

私はRVOがlvalueケースの世話をするので、それは区別できないように思っています(おそらくRVOのほんのわずかな利点があります)。しかし、あなたの最後の例(ローカル変数)は、とにかくそれをすべて解決します。 +1 – syam

+1

@syam:elisionは、(直接)一時変数またはローカルの自動変数を返すときにのみ許可されていると確信しています。確かに、私のコンパイラは* lvalue *を返すときにコピーを削除しません。 –

+0

また、 'auto c = a * b; 'のように使われた場合、戻り値はコピーではなくコピーを引き起こすので、'const' *' Object 'を返さないようにしてください。 – Xeo

関連する問題