Полагаю, я не понимаю, почему этот код работает с двумя std :: move ...
что подразумевает, что я до сих пор не понимаю, что делает std :: move
std::move
предназначен для того, чтобы сделать это явным в случаях, когда вы намереваетесь перейти от объекта. Семантика перемещения предназначена для работы с значениями . Таким образом, std::move()
принимает любое выражение (например, lvalue) и делает из него rvalue . Такое использование обычно возникает, когда необходимо разрешить передачу lvalue перегрузкам функций, которые принимают ссылку на значение в качестве параметра, например конструкторы перемещения и операторы присваивания ходов . Идея перемещения состоит в том, чтобы эффективно передавать ресурсы, а не делать копии.
В вашем фрагменте вы не используете std::move()
недопустимым образом , следовательно, этот код работает . В оставшейся части ответа мы попытаемся выяснить, является ли это использование выгодным или нет.
Должен ли я использовать std :: move для перехода в лямбду
Кажется, нет, у вас нет причин делать это во фрагменте. Прежде всего, вы звоните move()
на то, что безусловно уже является rvalue . Кроме того, синтаксически, set_callback()
получает аргумент std::function<bool(std::string)>
по значению, из которого ваша лямбда в настоящее время отлично инициализирует экземпляр.
Должен ли я использовать std :: move в функции set_callback ()
Не на 100% ясно, что вы получаете, используя переместить версию оператора присваивания в переменную-член m_callback
вместо обычного присваивания. Это не приведет к неопределенному поведению, поскольку вы не пытаетесь использовать аргумент после его перемещения. Кроме того, поскольку в C ++ 11 параметр callback
в set_callback()
будет сконструирован для перемещения для значений r , например, для вашего временного, и для копии, созданной для lvalue Например, если бы вы назвали это так:
auto func = [&](std::string s){ return p.print(s); };
w.set_callback(func);
Вам необходимо рассмотреть вопрос о том, лучше ли внутри метода перемещение, чем копирование в вашем случае. Перемещение включает в себя собственную реализацию назначения перемещения для соответствующего типа. Я не просто говорю здесь QOI, но учту, что при перемещении вам нужно освободить любой ресурс, который m_callback
удерживал до этой точки, и для сценария перехода от созданного экземпляра (как мы уже рассмотрели этот callback
была либо построена на основе копии, либо построена на основе ее аргумента), это добавляет к стоимости, которую уже имела эта конструкция. Не уверен, что такие движущиеся издержки применимы в вашем случае, но тем не менее ваша лямбда не так уж и дорога для копирования, как есть. Тем не менее, выбор двух перегрузок, одна из которых принимает const callback_fn& callback
и копирование внутри, а другая - callback_fn&& callback
и перемещение внутри, позволит полностью решить эту потенциальную проблему. Как и в любом из них, вы ничего не создаете для параметра, и в целом вы не обязательно высвобождаете старые ресурсы в качестве издержек, как при выполнении копирования-назначения, вы можете потенциально использовать уже существующие ресурсы LHS, копируя на них вместо того, чтобы выпускать его до перемещения из RHS.
Я знаю, что могу передавать по значению, но моя цель состояла в том, чтобы
что у меня нет его копии (идеальная пересылка?)
В контексте вывода типа (template
или auto
) T&&
представляет собой ссылку для пересылки , а не значение r * значение, Таким образом, вы должны написать функцию только один раз (шаблонная функция, без перегрузок), и полагаясь на std::forward
(эквивалент static_cast<T&&>
), убедитесь, что в любом случае использования описанный выше путь для использования двух перегрузки сохраняются с точки зрения стоимости, являющейся назначением копирования для вызова lvalue и назначением перемещения для вызова rvalue :
template<class T>
void set_callback(T&& callback)
{
m_callback = std::forward<T>(callback);
}