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

105

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

Hind Forsum
источник
Определите, пожалуйста, «безопасная работа». Какой безопасности вы ищете? безопасность управления сроком службы? Безопасность потоков?
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");
chema989
источник
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