Я видел довольно много кода в своей компании, где функции принимают аргументы rvalue.
Пример:
void Notifier::PostEvent(std::unique_ptr<IEvent>&& event)
{
std::unique_lock<std::mutex> lock(m_Mutex);
m_events.push_back(std::move(event));
m_conditionVariable.notify_all();
}
Здесь нет шаблонов. Это можно было бы легко написать так:
void Notifier::PostEvent(std::unique_ptr<IEvent> event)
{
std::unique_lock<std::mutex> lock(m_Mutex);
m_events.push_back(std::move(event));
m_conditionVariable.notify_all();
}
Поскольку параметр «событие» является значением приемника, в обоих случаях они фактически одинаковы. Я думаю, что единственным преимуществом первой версии является то, что она экономит один конструктор перемещения для unique_ptr. Это правильно? Это действительно того стоит?
Возможный дубликат Как передать аргумент unique_ptr конструктору или функции?
Ok. Теперь я лучше понимаю после прочтения Как передать аргумент unique_ptr конструктору или функции?
Происходит то, что в моем первом примере, где я перехожу по ссылке rvalue, это более или менее похоже на передачу по неконстантная ссылка lvalue. Хотя вы можете ожидать, что параметр будет пустым после вызова функции, это не гарантируется. Все зависит от того, что функция на самом деле делает с ним. Нажимая/перемещая его в вектор, как я делаю здесь, unique_ptr будет пустым. Однако, если я ничего не перемещаю (скажем, просто вызываю метод класса IEvent), тогда unique_ptr не пуст.
Таким образом, ссылочный параметр rvalue unique_ptr фактически не определяет гарантия того, что происходит со значением после вызова, т. е. является ли оно приемником или нет. Он может быть пустым после звонка, а может и не быть. Только изучив код, можно определить, что произойдет.
Оглядываясь назад, я думаю, что второе определение функции, в котором она принимает unique_ptr по значению, лучше. Это гарантирует, что unique_ptr был перемещен и больше не должен использоваться после этого.
Возможный дубликат Передача по значению против передачи по ссылке rvalue