Почему сброс std :: unique_ptr отличается от назначения? - PullRequest
0 голосов
/ 03 мая 2018

Я пытаюсь понять, почему

std::unique_ptr<MyClass> p = new MyClass; 

не работает, но

std::unique_ptr<MyClass> p;
p.reset(new MyClass);

в порядке. Я немного понимаю, чем они отличаются, но мне хотелось бы знать, почему был сделан выбор, чтобы сделать их разными. В чем опасность присвоения, которое не совпадает со сбросом?

Ответы [ 2 ]

0 голосов
/ 03 мая 2018

Я пытаюсь понять, почему std::unique_ptr<MyClass> p = new MyClass; не работает

Та же причина, что и упомянутая @songyuanyao, где объявлено explicit, говорит о том, что вы все равно можете инициализировать ее в другой форме инициализации , которая превосходит explicit:

// Valid, since now it's 'explicit'
std::unique_ptr<MyClass> p { new MyClass{} };
0 голосов
/ 03 мая 2018

Во-первых, std::unique_ptr<MyClass> p = new MyClass; - это не присвоение, это копия инициализации . И это не работает, потому что конструктор 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 конструкторы не учитываются при копировании инициализации (например, std::unique_ptr<MyClass> p = new MyClass;). Вы можете использовать их вместо прямой инициализации (например, std::unique_ptr<MyClass> p (new MyClass);). Они используются для запрета неявных преобразований, но вы можете выполнять явные преобразования. Как и при использовании reset, вы должны делать эти вещи явно , чтобы показать (и сделать себя), что вы почти уверены в том, что делаете.

Кстати: назначение из необработанного указателя также не работает, потому что std::unique_ptr не имеет перегруженного оператора присваивания, принимающего необработанный указатель в качестве параметра. По вышеуказанной причине необработанный указатель не может быть неявно преобразован в std::unique_ptr, поэтому оператор присваивания перемещения (который принимает std::unique_ptr в качестве параметра) также не будет рассматриваться.

...