在这种情况下,std :: move和std :: ref的区别

时间:2016-11-07 03:37:11

标签: c++11

当我更多地了解了在C ++ 11中引入的rvalue引用和std :: move时,我发现自己变得更加困惑。

看看这个例子:

我有将函数对象排入队列的函数模板:

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 :(得分:1)

在这种情况下,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 :: forward,因为调试器将进入std :: forward,我觉得很烦人。所以,这也是一个选择......

  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!