2016-11-07 60 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! 
相关问题