为啥 std::unique_ptr 重置与赋值不同?
Posted
技术标签:
【中文标题】为啥 std::unique_ptr 重置与赋值不同?【英文标题】:Why is std::unique_ptr reset not the same as assignment?为什么 std::unique_ptr 重置与赋值不同? 【发布时间】:2018-10-13 06:07:54 【问题描述】:我试图理解为什么
std::unique_ptr<MyClass> p = new MyClass;
不起作用,但是
std::unique_ptr<MyClass> p;
p.reset(new MyClass);
没问题。我有点理解它们的不同之处,但我想知道为什么选择让它们不同。赋值不等于reset有什么危险?
【问题讨论】:
std::unique_ptr<MyClass>
与 MyClass
的类型不同。
【参考方案1】:
首先,std::unique_ptr<MyClass> p = new MyClass;
不是赋值,而是copy initialization。而且它不起作用,因为采用原始指针的constructor of std::unique
被标记为explicit
:
explicit unique_ptr( pointer p ) noexcept;
它被声明为explicit
以避免意外(可能是危险的)隐式转换,例如:
void foo(std::unique_ptr<int> uptr);
int *rptr = new int;
foo(rptr); // suppose rptr is implicitly converted to std::unique_ptr<int>
// then the ownership is passed to the parameter uptr
// when foo() returns uptr is destroyed; the pointer managed by it is deleted too
// since rptr has been deleted continue to deference on it leads to UB
*rptr = 42; // UB
注意explicit
构造函数在copy initialization 中不被考虑(例如std::unique_ptr<MyClass> p = new MyClass;
)。您可以在direct initialization 中使用它们(例如std::unique_ptr<MyClass> p (new MyClass);
)。它们用于禁止隐式转换,但您可以执行显式转换。就像reset
的用法一样,您必须明确地 做这些事情,以表明(并让自己)您对自己在做什么非常确定。
顺便说一句:原始指针的赋值也不起作用,因为std::unique_ptr
没有将原始指针作为参数的重载赋值运算符。由于上述原因,原始指针不能隐式转换为std::unique_ptr
,因此也不会考虑移动赋值运算符(以std::unique_ptr
为参数)。
【讨论】:
但是std::unique_ptr<MyClass> p; p.reset (new MyClass); p = new MyClass;
确定是分配吗?仍然不允许。我可以看到函数调用,隐式构造函数是如何非常危险的。
@starmole:因为它可能意外发生。与意外键入“.reset()”相比,您更可能不小心将裸指针分配给 unique_ptr
。
请注意,如果您确实需要重新分配指针,您可以简单地执行p = std::unique_ptr<MyClass>(new MyClass);
,或者,如果您已经使用 C++14,则更好,p = std::make_unique<MyClass>()
。跨度>
@starmole 是的,如果有 std::unique_ptr<T>::operator = (T *)
会被调用。但请注意,这不仅有风险,而且毫无用处:无论如何,您都不应该让原始的拥有指针四处飘荡。
创建唯一指针的惯用方式是auto p = std::make_unique<MyClass>()
。在答案中这样说会很有用。【参考方案2】:
我试图理解为什么
std::unique_ptr<MyClass> p = new MyClass;
不工作
与@songyuanyao 提到的相同原因,它被声明为explicit
,告诉您仍然可以在超过explicit
的a different form of initialization 中初始化它:
// Valid, since now it's 'explicit'
std::unique_ptr<MyClass> p new MyClass ;
【讨论】:
以上是关于为啥 std::unique_ptr 重置与赋值不同?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我不能在 C++14 的 lambda 中移动 std::unique_ptr?
为啥 std::unique_lock 改变 std::unique_ptr?