为什么我需要移动' std::unique_ptr '



给定以下代码:

#include <iostream>
#include <memory>
struct A {};
struct B : public A {};
std::pair<bool, std::unique_ptr<B>> GetBoolAndB() {
return { true, std::make_unique<B>() };
}
std::unique_ptr<A> GetA1() {
auto[a, b] = GetBoolAndB();
return b;
}
std::unique_ptr<A> GetA2() {
auto [a, b] = GetBoolAndB();
return std::move(b);
}

GetA1无法编译,出现如下错误:

C2440: 'return': cannot convert from 'std::unique_ptr<B,std::default_delete<_Ty>>' to 'std::unique_ptr<A,std::default_delete<_Ty>>'

GetA2编译没有错误

我不明白为什么我需要调用std::move来使函数工作。

编辑

澄清一下,正如DanielLangr在评论中指出的那样,我的怀疑是关于

std::unique_ptr<A> GetA3() {
std::unique_ptr<B> b2; 
return b2;
}

编译和转移所有权而不需要std::move

现在我明白了,在GetA1GetA2的情况下,使用结构化绑定,b是某个对象的一部分,因此必须将其移动为右值引用。

我不明白为什么我需要调用std::move来使函数工作

因为std::unique_ptr对应的构造函数有一个右值引用类型的形参:

template< class U, class E >
unique_ptr( unique_ptr<U, E>&& u ) noexcept;

详情请参阅文档:https://en.cppreference.com/w/cpp/memory/unique_ptr/unique_ptr

由于右值引用不能绑定左值,因此不能使用b(它是左值)作为此构造函数的参数。

如果你想知道为什么breturn语句中被视为左值,请参见,例如:为什么结构化绑定禁用RVO和move on return语句?简而言之,b不是一个具有自动存储持续时间的变量,而是对pair元素的引用。

错误信息基本上只是说编译器找不到任何可行的转换构造函数,因此,它"不能转换…"。

通过用std::move调用包装b,您正在创建一个表达式,该表达式引用与b相同的对象,但它的类别是右值。可与构造函数形参绑定。

因为在任何时候都应该只有一个有效的unique_ptr。这就是为什么它被称为唯一的_ptr .

unique_ptr不可复制的,你必须移动它。
否则你最终会得到一个指针的副本,这将破坏它是唯一的意义!
参见:智能指针规则

最新更新