C++ Невозможно переместить unique_ptr с универсальными ссылками

Рассмотрим этот код:

template<typename T>
T mov(T&& t){
   return std::move(t);
}

int main(){
   std::unique_ptr<int> a = std::unique_ptr<int>(new int());
   std::unique_ptr<int> b = mov(a);
}

mov Функция должна просто взять универсальную ссылку и вернуть ее по значению, но moveэто вместо копирования. Таким образом, при вызове этого метода копирование не должно происходить. Следовательно, должно быть нормально вызывать такую ​​функцию с unique_ptr который может быть только перемещен. Тем не менее, этот код не компилируется: я получаю сообщение об ошибке:

test.cpp:24:34: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]’
    std::unique_ptr<int> b = mov(a);

Таким образом, кажется, что C++ пытается вызвать unique_ptrs конструктор копирования, который, конечно, удален. Но почему копия происходит здесь? Как я могу получить этот код для компиляции?

2 ответа

Решение

Я считаю, что ошибка в типе возврата mov

Код должен прочитать

#include <utility>
#include <memory>
template<typename T>
typename std::remove_reference<T>::type&& mov(T&& t){
   return std::move(t);
}

int main(){
   std::unique_ptr<int> a = std::unique_ptr<int>(new int());
   auto b = mov(a);
}

Вопрос намекал на сценарий возврата по стоимости, это также компилируется. Я не уверен, будет ли это работать в вашей ситуации;

template<typename T>
typename std::remove_reference<T>::type mov(T&& t){
   return std::move(t);
}

Я наконец нашел рабочее решение. Я думаю, что проблема заключается в возврате по значению, которое вызовет копию. Вместо этого мне нужен возврат по ссылке rvalue; тогда движение будет проведено автоматически. Сначала я попробовал это:

template<typename T>
T&& mov(T&& t){
   return std::move(t);
}

Но теперь проблема в том, что тип возвращаемого значения T&& это универсальная ссылка, а не ссылка на значение. Таким образом, при вызове функции с lvalue фактическая подпись T& mov(T& t), Из-за этого его тело не будет компилироваться, потому что я не могу std::move на ссылку lvalue. Это именно то, что произошло, вот ошибка:

test.cpp:18:22: error: invalid initialization of non-const reference of type 

‘std::unique_ptr<int>&’ from an rvalue of type ‘std::remove_reference<std::unique_ptr<int>&>::type {aka std::unique_ptr<int>}’
    return std::move(t);

Итак, мне нужен реальный rvalue ссылка в качестве возвращаемого типа. Сначала я не знал, как его построить, но, наконец, я понял, что мне сначала нужно std::remove_reference тип T а затем добавить &&тогда у меня будет реальная ссылка T&&, И это сработало, эта версия mov прекрасно компилируется и решает проблему:

template<typename T>
typename std::remove_reference<T>::type&& mov(T&& t){
   return std::move(t);
}

Как сказал Найл, возврат по ссылке также работает с использованием remove_reference без &&:

template<typename T>
typename std::remove_reference<T>::type mov(T&& t){
   return std::move(t);
}
Другие вопросы по тегам