为什么我需要移动 `std::unique_ptr`
Why do I need to move `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
即可编译和转移所有权。
现在我了解到,在 GetA1
和 GetA2
的情况下,使用结构化绑定时 b
是 某些对象的一部分 , 因此必须将其移动成为右值引用。
I don't understand why I need to call std::move to make the function work.
因为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
(即左值)作为此构造函数的参数。
如果您想知道为什么 b
在 return
语句中被视为左值,请参见,例如: 简而言之,b
不是一个变量自动存储持续时间,而是对成对元素的引用。
错误消息基本上只是说编译器找不到任何可行的转换构造函数,因此,它“无法转换...”。
通过用 std::move
调用包装 b
,您正在创建一个表达式,它引用与 b
完全相同的对象,但它的类别是右值。这可能与该构造函数参数绑定。
因为任何时候都应该只有一个有效的unique_ptr
。
这就是为什么它被称为 unique_ptr.
unique_ptr
不可复制,必须移动它。
否则你最终会得到一个指针的副本,这会破坏它的独特性!
参见:Rules for Smart Pointers
给定以下代码:
#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
即可编译和转移所有权。
现在我了解到,在 GetA1
和 GetA2
的情况下,使用结构化绑定时 b
是 某些对象的一部分 , 因此必须将其移动成为右值引用。
I don't understand why I need to call std::move to make the function work.
因为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
(即左值)作为此构造函数的参数。
如果您想知道为什么 b
在 return
语句中被视为左值,请参见,例如: b
不是一个变量自动存储持续时间,而是对成对元素的引用。
错误消息基本上只是说编译器找不到任何可行的转换构造函数,因此,它“无法转换...”。
通过用 std::move
调用包装 b
,您正在创建一个表达式,它引用与 b
完全相同的对象,但它的类别是右值。这可能与该构造函数参数绑定。
因为任何时候都应该只有一个有效的unique_ptr
。
这就是为什么它被称为 unique_ptr.
unique_ptr
不可复制,必须移动它。
否则你最终会得到一个指针的副本,这会破坏它的独特性!
参见:Rules for Smart Pointers