没有调用std :: function move构造函数

时间:2014-01-23 11:42:09

标签: c++ c++11 constructor

考虑以下代码:

void makeNew(std::function<void()>&& func)
{
    std::function<void()> p = func;
}

void test(){}

用法:

makeNew(std::bind(test));

预期结果:

根据std::function<void()>的结果类型创建的临时std::bind(test)对象 然后将这个临时的std :: function对象作为rvalue引用传递给makeNew,然后移动std :: function p = func时调用的构造函数;被调用。

实际发生了什么(使用VS2010并使用调试器进行踩踏):

对于以下语句std::function<void()> p = func;,将调用复制构造函数而不是移动构造函数。

有人可以解释这种行为吗?

2 个答案:

答案 0 :(得分:4)

右值引用不是右值(除了从函数返回的值)。它只是一种不同类型的左值,具有与普通参考不同的绑定规则。

如果要从右值引用移动,请使用std::move,与任何其他引用相同。 std::move返回一个右值引用类型,因此表达式std::move(func)是一个xvalue,因此 是一个右值,可以从中移动。 func是一个左值,即使它有rvalue-reference类型。

请注意,需要一个采用右值引用的函数非常罕见。你要这样做是为了排除左值,要么是因为你想要防止它们被传入,要么是因为你有一个不同的左值重载。最常见的情况是您希望函数从右值移动或复制左值。所以你可以改为按值取值并从中移出(如约瑟夫的答案),与编写两个不同函数的麻烦相比,开销很小或没有开销。

答案 1 :(得分:2)

您正在错误地使用右值引用。通过右值参考进行参数并不是一件非常普遍的事情。它没有说“我想从论证中移出”而且它没有说“我想稍后从这个参数中移出”。相反,它是一个参考 - 没有被复制或移动,它只是被引用。在函数内部,表达式func是左值(因为命名的内容是左值),因此在使用它初始化p时将调用复制构造函数。

你应该做的是通过值来获取参数:

void makeNew(std::function<void()> p)
{
  // ...
}

如果将rvalue传递给此函数,它将被移动到该函数中。如果您传递左值,它将被复制。看,现在没有必要在std::function内额外makeNew。只需使用参数本身!如果由于某种原因你真的需要离开参数,那么你可以这样做:

void makeNew(std::function<void()> func)
{
  std::function<void()> p = std::move(func);
}

使用std::move将表达式func(这是一个左值)转换为右值表达式。然后它将被移动。但是,除非你进入另一个功能,否则我看不出有任何理由需要这样做。

当然,如果我完全错了并且您确实想要采用右值参考,那么如果您想要从中移动,您仍然需要std::move