4

考虑这段代码:

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因此,使用只能移动的 a 调用这样的函数应该没问题。但是,此代码无法编译:我收到错误:

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当然被删除的复制构造函数。但是为什么这里会出现副本呢?我怎样才能让这段代码编译?

4

2 回答 2

3

我相信错误是在返回类型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);
}
于 2014-07-22T10:44:12.807 回答
3

我终于找到了一个可行的解决方案。我认为问题在于按值返回会触发副本。相反,我需要通过右值引用返回;然后将自动进行移动。首先我尝试了这个:

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

但是现在,问题在于返回类型T&&通用引用,而不是右值引用。因此,当使用左值调用函数时,实际签名是T& mov(T& t). 因此,它的主体将无法编译,因为我无法std::move获得左值引用。这正是发生的事情,这是错误:

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);

所以,我需要一个真正的右值引用作为返回类型。起初,我不知道如何构造它,但最后,我发现我首先需要std::remove_referencetype T,然后 add &&,然后我会有一个真正的 rvalue reference T&&。它有效,这个版本的mov编译很好并解决了问题:

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

正如 Niall 所说,通过引用返回也可以使用remove_referencewithout &&

template<typename T>
typename std::remove_reference<T>::type mov(T&& t){
   return std::move(t);
}
于 2014-07-22T10:43:31.530 回答