2016-11-07 98 views
1

當我學習了更多關於在C++ 11中引入的右值引用和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)) 

看起來他們都很好。 但他們之間有什麼區別。在哪種情況下,我應該使用其中的一種。

+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::forwardstatic_cast而不是std::move,因爲您不知道您得到的是否實際上是右值引用。

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

就個人而言,我更喜歡乾脆直接static_casting而不是使用的std ::前進,因爲調試器將步入的std ::前,我發現很煩人。所以,這也是一個選項...

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

最後,至於std::ref去,一個包裝函數對象的std::reference_wrapper,只有持有該函數對象的引用。這意味着你沒有將對象的所有權傳遞給push中的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! 
相關問題