当我更多地了解了在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))
看起来所有这些都运作良好。 但他们之间的区别是什么。我应该在哪种情况下使用其中一种。
答案 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::forward
或static_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!