这里是否需要“std::move”

Is `std::move` necessary here?

本文关键字:move std 是否 这里      更新时间:2023-10-16

以下代码段中是否需要std::move

std::function<void(int)> my_std_function;
void call(std::function<void(int)>&& other_function)
{
  my_std_function.swap(std::move(other_function));
}

据我所知,call()接受右值引用。。但由于右值引用本身就是一个左值,为了调用swap(std::function<void(int)>&&),我必须将其重新转换为具有std::move 的右值引用

我的推理正确吗?或者std::move在这种情况下可以省略(如果可以,为什么?)

std::function::swap不通过右值引用获取其参数。它只是一个常规的非const左值引用。因此std::move是没有帮助的(并且可能不应该编译,因为右值引用不允许绑定到非const左值引用)。

other_function也不需要是一个右值引用。

签名是

void std::function<Sig>::swap( function& other )

因此代码不应该使用std::move进行编译(msvc具有允许此绑定的扩展:/)

当你使用r值参考时,我认为在你的情况下,一个简单的赋值就是你想要的:

std::function<void(int)> my_std_function;
void call(std::function<void(int)>&& other_function)
{
  my_std_function = std::move(other_function); // Move here to avoid copy
}

在这种情况下,std::function::swap采用非常量左值引用,这并没有什么区别。它甚至不应该使用std::move进行编译。

如果您使用的函数确实允许右值,那么需要调用std::move,因为other_function是一个左值,即使它的类型是右值引用。例如:

struct Foo {
    Foo()=default;
    Foo(const Foo&) { std::cout << "copy" << std::endl; }
    Foo(Foo&&) { std::cout << "move" << std::endl; }
};
void bar (Foo&& a) {
    Foo b {a};            //copy
    Foo c {std::move(a)}; //move
}

从某种意义上说,你是对的—要再次获得右值,您需要std::move

但是,swap调用不需要右值或右值引用—只是一个普通的ol’lvalue参考

所以你可以不用std::move演员阵容。

就移动语义而言,交换操作是相当低级的。您会发现,最有用的移动最终是通过一系列交换来实现的,因此交换本身不使用移动语义是有道理的。真的,他们会怎么做?