为什么std :: unique_ptr重置与赋值不一样?

sta*_*ole 11 c++ initialization variable-assignment unique-ptr c++11

我想知道为什么

std::unique_ptr<MyClass> p = new MyClass; 
Run Code Online (Sandbox Code Playgroud)

不起作用,但是

std::unique_ptr<MyClass> p;
p.reset(new MyClass);
Run Code Online (Sandbox Code Playgroud)

很好.我有点理解他们是如何不同的,但我想知道为什么做出选择使他们与众不同.分配与重置不一样的危险是什么?

son*_*yao 19

首先,std::unique_ptr<MyClass> p = new MyClass;不是赋值,它是复制初始化.并且它不起作用,因为获取原始指针的构造函数std::unique标记为explicit:

explicit unique_ptr( pointer p ) noexcept;
Run Code Online (Sandbox Code Playgroud)

它被声明为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
Run Code Online (Sandbox Code Playgroud)

请注意,explicit复制初始化中不考虑构造函数(例如std::unique_ptr<MyClass> p = new MyClass;).您可以在直接初始化中使用它们(例如std::unique_ptr<MyClass> p (new MyClass);).它们用于禁止隐式转换,但您可以执行显式转换.就像使用一样reset,你必须明确地做这些事情,以显示(并使自己)你非常确定你正在做什么.

BTW:来自原始指针的赋值也不起作用,因为std::unique_ptr没有重载赋值运算符将原始指针作为参数.由于上述原因,原始指针不能隐式转换为std::unique_ptr,因此std::unique_ptr也不会考虑移动赋值运算符(作为参数).

  • @starmole:因为它可能会偶然发生*.你更不可能意外地将一个裸指针分配给`unique_ptr`,而不是意外地键入".reset()". (6认同)
  • 请注意,在您实际需要重新分配指针的情况下,您可以简单地执行`p = std :: unique_ptr <MyClass>(new MyClass);`或者,更好的是,如果您已经在C++ 14上, p = std :: make_unique <MyClass>()`. (2认同)

Dea*_*Seo 6

我试图理解为什么 std::unique_ptr<MyClass> p = new MyClass; 不起作用

与@songyuanyao提到的相同的原因,在声明的地方,它explicit告诉你仍然可以不同的初始化形式初始化它,超过explicit:

// Valid, since now it's 'explicit'
std::unique_ptr<MyClass> p { new MyClass{} };
Run Code Online (Sandbox Code Playgroud)