Могут ли С ++ 11 unique_ptr и shared_ptr преобразовывать в типы друг друга?


105

Предоставляет ли стандартная библиотека C ++ 11 какие-либо утилиты для преобразования из a std::shared_ptrв std::unique_ptrили наоборот? Это безопасная операция?


Определите, пожалуйста, «безопасная работа». Какой безопасности вы ищете? безопасность управления сроком службы? Безопасность потоков?
jaggedSpire

2
«STL» не означает стандартную библиотеку. STL тут ни при чем shared_ptr.
curiousguy

1
@jaggedSpire Безопасность потоков означает, что у вас есть владельцы, используемые в разных потоках, то есть количество использований не равно 1.
curiousguy

@curiousguy Я знал это. Моя точка зрения заключалась в том, что «безопасность» не была четко определена в вопросе OP, и ему нужно было прояснить, какой вид «безопасности» он имел в виду, поскольку существует несколько видов.
jaggedSpire

Ответы:


172

std::unique_ptr- это способ выражения исключительного владения в C ++ 11, но одной из самых привлекательных его особенностей является то, что он легко и эффективно преобразуется в std::shared_ptr.

Это ключевая часть того, почему std::unique_ptrон так хорошо подходит в качестве возвращаемого типа заводской функции. Фабричные функции не могут знать, захотят ли вызывающие стороны использовать семантику исключительного владения для возвращаемого объекта, или совместное владение (т. Е. std::shared_ptr) Будет более подходящим. Возвращая a std::unique_ptr, фабрики предоставляют вызывающим объектам наиболее эффективный интеллектуальный указатель, но они не мешают вызывающим объектам заменить его более гибким аналогом.

std::shared_ptrк std::unique_ptrне допускается. После того, как вы перешли на управление жизненным циклом ресурса std::shared_ptr, вы уже не передумаете. Даже если количество ссылок равно единице, вы не можете вернуть себе право собственности на ресурс, чтобы, скажем, std::unique_ptrуправлять им.

Ссылка: Эффективный современный C ++. 42 СПОСОБА УЛУЧШИТЬ ИСПОЛЬЗОВАНИЕ C ++ 11 И C ++ 14. Скотт Мейерс.

Короче говоря, вы можете легко и эффективно преобразовать std::unique_ptrв, std::shared_ptrно не можете преобразовать std::shared_ptrв std::unique_ptr.

Например:

std::unique_ptr<std::string> unique = std::make_unique<std::string>("test");
std::shared_ptr<std::string> shared = std::move(unique);

или:

std::shared_ptr<std::string> shared = std::make_unique<std::string>("test");

9
...Как ты делаешь это?
Джейк

4
@Jake Я добавил пример
chema989 09

Имейте в виду, что, хотя это не разрешено, компилятор (по крайней мере, не gcc) на самом деле не предотвратит (или даже предупредит), если вы случайно (например, изменив тип указателя переменной-члена) назначите a std::unique_ptrдля std::shared_ptr.
StefanQ


@StefanQ Почему вы думаете, что нельзя назначать a std::unique_ptrна a std::shared_ptr? Стандартная библиотека определяет оператор присваивания перемещения template<class Y, class Deleter> shared_ptr& operator=(std::unique_ptr<Y, Deleter>&& r); для std::shared_ptr<T>.
cuddlebugCuller

-8

Учитывая unique_ptr u_ptr, создайте shared_ptr s_ptr:

std::shared_ptr<whatever> s_ptr(u_ptr.release());

Идти другим путем нецелесообразно.


29
Вот «правильный» путь:std::shared_ptr<whatever> s_ptr(std::move(u_ptr));
emlai

6
А вот педантичный «правильный» путь:std::shared_ptr<whatever> s_ptr{std::move(u_ptr)};
polyvertex

3
Что в этом менее безопасно?
nmr

7
@VioletGiraffe • Я полагаю, что polyvertex выступает за использование нового синтаксиса списка инициализации, который позволяет избежать тихих сужающих преобразований и обеспечивает инициализацию членов с помощью единообразного синтаксиса, как хорошую привычку. Шесть из одного, полдюжины из другого?
Eljay

9
@nmr Это небезопасно, потому что вы можете потерять то, что Deleterхранится внутриunique_ptr
Zang MingJie
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.