Есть функция, принимающая rvalue ссылку и передающая её другой функции, принимающей rvalue ссылку:
void inner(int&& a)
{/* ... */}
void outer(int&& a)
{
inner(std::move(a));
}
Я написал std::move
, потому что для передачи rvalue ссылок мы вроде как используем std::move
. Но есть подозрение, что в данном случае будет вызвана лишняя операция перемещения и для её исключения, возможно, стоит вызвать std::forward
, чтобы передать ссылку напрямую, а не создавать временные объекты и перемещать содержимое между ними:
void outer(int&& a)
{
inner(std::forward(a));
}
Подскажите, пожалуйста, какой вариант правильней?
Вообще-то, ни в первом, ни во втором случае сами move
и forward
ни к каким действиям не приводят, и никаких лишних перемещений не вызывают.
Как по мне, правильнее и логичнее применение move
- потому что у вас четко передается rvalue, а не универсальная ссылка, которая может быть и l, и r (в случае шаблонной функции) - и когда нужно просто передать то, что было получено, т.е. lvalue оставить lvalue, а rvalue - rvalue. Это не ваш случай.
По-моему, так. (с) Пух
std::forward
требует явного указания шаблонного аргумента и имеет смысл использовать только в контексте шаблонов в универсальными ссылками, которые могут разворачиваться как в rvalue, так и в lvalue. То, что вы написали, а именно std::forward(a)
просто напросто не скомпилируется.
Т.к. ваши функции принимают rvalue ссылки, то std::move
тут единственный правильный выбор. С тем же эффектом можно было бы написать inner(std::forward<S>(a))
, но это длиннее.
Ни std::move
, ни std::forward
никогда ничего не перемещают. Они только изменяют квалификаторы ссылочности. Для int
это вообще не актуально, но если у вас есть класс c конструктором перемещения и копирования, эти квалификаторы ссылочности позволяют выбрать нужный конструктор. Изменение квалификаторов происходит так:
#include <type_traits>
#include <utility>
struct Foo{
int v = 0;
Foo() = default;
Foo(int v_): v{v_} {}
Foo(const Foo&) = default;
Foo(Foo&&) = default;
};
void test(){
Foo f1;
Foo& ref_foo = f1;
const Foo& const_ref_foo = ref_foo;
static_assert(std::is_same< Foo&& , decltype(std::move(ref_foo))>{}, "");
static_assert(std::is_same< const Foo&&, decltype(std::move(const_ref_foo))>{}, "");
static_assert( std::is_convertible< const Foo&&, const Foo&>{}, ""); // const Foo&& может вызвать конструктор копирования
static_assert( ! std::is_convertible< const Foo&&, Foo&&>{}, ""); // const Foo&& не может вызвать конструктор перемещения
static_assert(std::is_same< Foo&& , decltype(std::forward<Foo>(f1))>{}, ""); // Вызовет конструктор перемещения
static_assert(std::is_same< Foo& , decltype(std::forward<Foo&>(ref_foo))>{}, ""); // Вызовет конструктор копирования
static_assert(std::is_same< const Foo&&, decltype(std::forward<const Foo>(const_ref_foo))>{}, ""); // Вызовет конструктор копирования
}
Т.е. в случае
void inner(Foo&& a){
}
void outer(Foo&& a){
inner(std::move(a));
}
При вызове inner
ни копирования, ни перемещения не произойдет, будет просто передана ссылка. А вот при таком использовании:
void inner(Foo&& a){
static Foo v = std::move(a);
}
void outer(Foo&& a){
inner(std::move(a));
}
При вызове outer
произойдет ровно одно перемещение, причем в теле inner
, а не outer
.
Частный дом престарелых в Киеве: комфорт, забота и профессиональный уход
Есть проект, в нем обрабатывает внешняя библиотека, у которой есть функции обратного вызоваКогда происходит событие функция обратного вызова...
На строке hr = pEnum->Next(WBEM_INFINITE, 1, &pObject, &returned); выкидывает ошибку IDispatch error #3587, почему это происходит и как это можно исправить?
Имеется программа которая просто скачивает файл и записывает на рабочий стол, все хорошо программа скачивает, но вот в чем проблема антивирусник...
Ситуация такая есть у меня библиотека-кликер и я хочу написать несколько функций которые бы работали не через winapi эмулируя клавиатуру, мышь...