Здесь `std:: move` необходимо?
Требуется ли 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()
принимает ссылку на rvalue.. но так как ссылка rvalue сама является lvalue, для вызова swap(std::function<void(int)>&&)
мне нужно переставить это значение в ссылку rvalue с помощью std::move
Могут ли мои рассуждения правильные или std::move
в этом случае могут быть опущены (и если это возможно, почему?)
Ответы
Ответ 1
std::function::swap
не принимает свой параметр по ссылке rvalue. Это просто регулярная ссылка const
lvalue. Таким образом, std::move
бесполезен (и, вероятно, не должен компилироваться, поскольку ссылки rvalue не могут связываться с ссылками lvalue).
other_function
также не обязательно должен быть ссылкой rvalue.
Ответ 2
Подпись
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
}
Ответ 3
В этом случае это не имеет значения, поскольку std::function::swap
принимает ссылку на константу lvalue. Он даже не должен компилироваться с помощью std::move
.
Если вы использовали функцию, которая разрешала rvalues, тогда вам нужно было бы вызвать std::move
, поскольку other_function
является значением lvalue, хотя тип его является ссылкой rvalue. Например:
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
}
Ответ 4
Вы правы в определенном смысле; чтобы снова получить rvalue, вам понадобится std::move
.
Однако для вызова swap
не требуется rvalue или rvalue reference — просто равная ссылка.
Итак, вы можете пойти без кавычек std::move
.
В терминах семантики перемещения операция свопинга довольно низкоуровневая. Вы обнаружите, что большинство полезных шагов в конечном итоге реализованы рядом свопов, поэтому имеет смысл, что сами свопы не используют семантику перемещения. Действительно, как они?