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_ptr
s конструктор копирования, который, конечно, удален. Но почему копия происходит здесь? Как я могу получить этот код для компиляции?
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);
}