¿C ++ 11 unique_ptr y shared_ptr pueden convertirse al tipo de cada uno?

99

¿La biblioteca estándar de C ++ 11 proporciona alguna utilidad para convertir de a std::shared_ptra std::unique_ptr, o viceversa? ¿Es esta operación segura?

Hind Forsum
fuente
Defina "operación segura" por favor. ¿Qué tipo de seguridad busca? seguridad de gestión de por vida? ¿Seguridad del hilo?
jaggedSpire
2
"STL" no significa biblioteca estándar. El STL no tiene nada que ver shared_ptr.
curioso
1
@jaggedSpire La seguridad de los subprocesos significaría que tiene propietarios utilizados en diferentes subprocesos, es decir, el recuento de uso no es 1.
Curioso
@curiousguy lo sabía. Mi punto era que la "seguridad" no estaba bien definida en la pregunta de OP, y necesitaba aclarar a qué tipo de "seguridad" se refería, ya que hay varios tipos.
jaggedSpire

Respuestas:

161

std::unique_ptres la forma en que C ++ 11 expresa la propiedad exclusiva, pero una de sus características más atractivas es que se convierte fácil y eficientemente a std::shared_ptr.

Esta es una parte clave de por qué std::unique_ptres tan adecuado como tipo de retorno de función de fábrica. Las funciones de fábrica no pueden saber si las personas que llaman querrán utilizar la semántica de propiedad exclusiva para el objeto que devuelven o si la propiedad compartida (es decir, std::shared_ptr) sería más apropiada. Al devolver un std::unique_ptr, las fábricas proporcionan a las personas que llaman el puntero inteligente más eficiente, pero no impiden que las personas que llaman lo reemplacen con su hermano más flexible.

std::shared_ptrque std::unique_ptrno está permitido. Una vez que haya entregado la gestión de por vida de un recurso a un std::shared_ptr, no hay forma de cambiar de opinión. Incluso si el recuento de referencias es uno, no puede reclamar la propiedad del recurso para, por ejemplo, std::unique_ptradministrarlo.

Referencia: C ++ moderno efectivo. 42 FORMAS ESPECÍFICAS DE MEJORAR EL USO DE C ++ 11 Y C ++ 14. Scott Meyers.

En resumen, puede convertir un std::unique_ptra de manera fácil y eficiente, std::shared_ptrpero no puede convertir std::shared_ptra std::unique_ptr.

Por ejemplo:

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

o:

std::shared_ptr<std::string> shared = std::make_unique<std::string>("test");
chema989
fuente
9
...¿Cómo lo haces?
Jake
4
@Jake He agregado un ejemplo
chema989
Tenga en cuenta que, si bien no está permitido, el compilador (al menos no gcc) en realidad no evitará (ni siquiera advertirá) si accidentalmente (por ejemplo, al cambiar el tipo de puntero de una variable miembro) asigna a std::unique_ptra a std::shared_ptr.
StefanQ
-8

Dado unique_ptr u_ptr, cree shared_ptr s_ptr:

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

Ir por el otro lado no es práctico.

nmr
fuente
29
Esta es la forma "correcta":std::shared_ptr<whatever> s_ptr(std::move(u_ptr));
emlai
6
Y aquí está la forma pedante "correcta":std::shared_ptr<whatever> s_ptr{std::move(u_ptr)};
polyvertex
3
¿Qué tiene de menos seguro?
nmr
7
@VioletGiraffe • Supongo que polyvertex aboga por el uso de la nueva sintaxis de la lista de inicialización, que evita las conversiones de reducción silenciosas y acomoda la inicialización de miembros con una sintaxis uniforme, como un buen hábito. ¿Seis de uno, media docena de los otros?
Eljay
8
@nmr No es seguro porque puede perder lo Deleteralmacenado dentro delunique_ptr
Zang MingJie