C++ std::未调用函数移动构造函数

C++ std::未调用函数移动构造函数,c++,c++11,constructor,C++,C++11,Constructor,考虑以下代码: void makeNew(std::function<void()>&& func) { std::function<void()> p = func; } void test(){} 预期结果: 临时std::function从std::bind(test) 然后这个临时std::function对象作为右值引用传递给makeNew,然后在std::function p=func时调用move构造函数;被调用 实际发生的情况(

考虑以下代码:

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

void test(){}
预期结果:

临时
std::function
std::bind(test)
然后这个临时std::function对象作为右值引用传递给makeNew,然后在std::function p=func时调用move构造函数;被调用

实际发生的情况(使用VS2010和带调试器的单步执行):

对于以下语句
std::function p=func,将调用复制构造函数而不是移动构造函数


有人能解释一下这种行为吗?

您使用的右值引用不正确。通过右值引用获取参数不是一件很常见的事情。它没有说“我想从参数中移动”,也没有说“我想以后从这个参数中移动”。相反,它是一个引用-没有任何东西被复制或移动,它只是引用。在函数内部,表达式
func
是一个左值(因为被命名的东西都是左值),因此在初始化
p
时将调用复制构造函数

您应该做的是按值获取参数:

void makeNew(std::function<void()> p)
{
  // ...
}
使用
std::move
将表达式
func
(左值)转换为右值表达式。然后,它将从。然而,我看不出有什么好的理由需要这样做,除非你进入另一个函数


当然,如果我完全错了,并且你真的想使用右值引用,那么如果你想离开它,你仍然需要执行
std::move

你不正确地使用右值引用。通过右值引用获取参数不是一件很常见的事情。它没有说“我想从参数中移动”,也没有说“我想以后从这个参数中移动”。相反,它是一个引用-没有任何东西被复制或移动,它只是引用。在函数内部,表达式
func
是一个左值(因为被命名的东西都是左值),因此在初始化
p
时将调用复制构造函数

您应该做的是按值获取参数:

void makeNew(std::function<void()> p)
{
  // ...
}
使用
std::move
将表达式
func
(左值)转换为右值表达式。然后,它将从。然而,我看不出有什么好的理由需要这样做,除非你进入另一个函数

当然,如果我完全错了,你真的想得到一个右值引用,如果你想离开它,你仍然需要做
std::move
右值引用不是右值(从函数返回时除外)。它只是一种不同类型的左值,具有与普通引用不同的绑定规则

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

注意,很少需要一个接受右值引用的函数。这样做是为了排除左值,或者是因为你想阻止它们被传入,或者是因为你有一个左值重载,它做了一些不同的事情。最常见的情况是希望函数从右值移动或复制左值。因此,您可以按值获取参数并从中移动(如Joseph的回答中所示),与编写两个不同函数相比,几乎没有开销。

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

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


注意,很少需要一个接受右值引用的函数。这样做是为了排除左值,或者是因为你想阻止它们被传入,或者是因为你有一个左值重载,它做了一些不同的事情。最常见的情况是希望函数从右值移动或复制左值。因此,您可以按值获取参数并从中移动(如Joseph的回答中所示),与编写两个不同函数相比,几乎没有开销。

func
i为左值。您可以使用std::move将其转换为右值,右值可以从.
func
i移动为左值。您可以使用std::move将其转换为右值,右值可以从中移动。std::move不是强制转换为&&@JobNick吗?右值引用类型变量的名称是左值。返回右值引用的函数是右值。
std::move
所依赖的就是这个小怪癖。std::move不就是强制转换到&&@JobNick吗?右值引用类型变量的名称是左值。返回右值引用的函数是右值。这就是
std::move
所依赖的这个小怪癖。
void makeNew(std::function<void()> func)
{
  std::function<void()> p = std::move(func);
}