2016-11-07 18 views
1

C++ 11で導入されたrvalue参照とstd :: moveについて詳しく知ると、もっと混乱しています。この例ではこの場合のstd :: moveとstd :: refの相違点

ルック:

私は関数オブジェクトをエンキュー関数テンプレートがあります。

template<typename F, typename... Args> 
void push(F && f, Args&&... args){ 
    std::function<int(int)> func = f; 
    //Here function_queue is a object of queue<std::function<int(int)>> 
    function_queue.push(std::move(f)); 
} 

を私は三つの方法でプッシュを呼び出すことができます

int foo(int i){return i;} 

この機能を持っています:

1. push(foo) 
2. push(std::move(foo)) 
3. push(std::ref(foo)) 

すべてがうまくいくように見えます。 しかし、それらの違いは何ですか?どのシナリオでは、私は他のシナリオに対してそれらの1つを使うべきですか?

+0

また、 'f'をキュー' push(std :: forward (f)) 'に転送することもできます。 –

答えて

0

この場合、実際に関数に渡すものは古い関数ポインタであるため、1と2の間に違いはありません。ポインタを移動することはコピーと同じです。したがって、ポインタはすべて同じことを行います。

はしかし、

struct dude { 
    std::vector<int> data; 

    int operator()(int) const { return 0; } 
} 

dude whoa{5,6,7,8,9}; 

push(whoa); // copies the dude's data 
push(std::move(whoa)); // moves the dude's data! 

は、その後の動きが有意義になり、より高速

...あなたはこのようないくつかのヘビーデューティー状態を持つ関数オブジェクトを持っていると言います。また、プッシュの内部に std::moveの代わりに std::forwardまたは static_castのいずれかを使用してください。実際には値が実際の値であるかどうかわからないためです。

function_queue.push(std::forward<F &&>(f)); 

個人的に、私は、デバッガが、私は非常に迷惑見つけたのstd ::前方にステップするので、ちょうど直接、代わりに前方:: STDを使用してのstatic_casting好みます。だから、これもオプションです...

function_queue.push(static_cast<F &&>(f)); 

は最後に、限りstd::refが行くように、それが唯一の関数オブジェクトへの参照を保持しているstd::reference_wrapperでの関数オブジェクトをラップしています。これは、オブジェクトの所有権をプッシュのstd :: functionに渡すのではなく、オブジェクトがスコープから外れている場合は、ダングリング参照があることを意味します。ただし、参照されている関数オブジェクトが常に存在することがわかっている場合は、関数オブジェクトのコピーと移動は行われません。たとえば...

{ 
    dude whoa{1,2,3,4}; 
    push(std::ref(whoa)); 
} 
// whoa is out of scope here, and the std::function 
// which grabbed the std::reference_wrapper object holds a dangling reference! 
関連する問題