O C ++ 11 unique_ptr e shared_ptr podem ser convertidos para o tipo um do outro?

99

A biblioteca padrão do C ++ 11 fornece algum utilitário para converter de a std::shared_ptrpara std::unique_ptrou vice-versa? Esta operação é segura?

Hind Forsum
fonte
Defina "operação segura", por favor. Que tipo de segurança você está procurando? segurança de gerenciamento de vida? Segurança da linha?
jaggedSpire de
2
"STL" não significa biblioteca padrão. O STL não tem nada a ver com shared_ptr.
curioso
1
@jaggedSpire A segurança do thread significa que você tem proprietários usados ​​em diferentes threads, ou seja, a contagem de uso não é 1.
curioso
@curiousguy eu sabia disso. Meu ponto era que "segurança" não estava bem definida na pergunta de OP, e ele precisava esclarecer a que tipo de "segurança" ele se referia, pois existem vários tipos.
jaggedSpire

Respostas:

161

std::unique_ptré a maneira do C ++ 11 de expressar propriedade exclusiva, mas um de seus recursos mais atraentes é que ele pode ser convertido de forma fácil e eficiente em um std::shared_ptr.

Essa é uma parte importante do motivo std::unique_ptrpelo qual é tão adequado como um tipo de retorno de função de fábrica. As funções de fábrica não podem saber se os chamadores desejarão usar a semântica de propriedade exclusiva para o objeto que retornam ou se a propriedade compartilhada (ou seja, std::shared_ptr) seria mais apropriada. Ao retornar um std::unique_ptr, as fábricas fornecem aos chamadores o ponteiro inteligente mais eficiente, mas não impedem que os chamadores o substituam por seu irmão mais flexível.

std::shared_ptrpara std::unique_ptrnão é permitido. Depois de transformar o gerenciamento vitalício de um recurso em um std::shared_ptr, não há como mudar de ideia. Mesmo que a contagem de referência seja um, você não pode reivindicar a propriedade do recurso para, digamos, std::unique_ptrgerenciá-lo.

Referência: C ++ moderno eficaz. 42 MANEIRAS ESPECÍFICAS DE MELHORAR O USO DE C ++ 11 E C ++ 14. Scott Meyers.

Resumindo, você pode converter um std::unique_ptrpara de maneira fácil e eficiente, std::shared_ptrmas não std::shared_ptrpara std::unique_ptr.

Por exemplo:

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

ou:

std::shared_ptr<std::string> shared = std::make_unique<std::string>("test");
chema989
fonte
9
...Como você faz isso?
Jake
4
@Jake Eu adicionei um exemplo
chema989
Esteja ciente de que embora não seja permitido, o compilador (pelo menos não o gcc) na verdade não impedirá (ou mesmo avisará) se você acidentalmente (por exemplo, alterando o tipo de ponteiro de uma variável de membro) atribuir a std::unique_ptra a std::shared_ptr.
StefanQ
-8

Dado unique_ptr u_ptr, crie shared_ptr s_ptr:

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

Seguir o outro caminho não é prático.

nmr
fonte
29
Esta é a maneira "certa":std::shared_ptr<whatever> s_ptr(std::move(u_ptr));
emlai
6
E aqui está o caminho "certo" pedante:std::shared_ptr<whatever> s_ptr{std::move(u_ptr)};
polyvertex
3
O que é menos seguro nisso?
NMR
7
@VioletGiraffe • Suponho que o polyvertex esteja defendendo o uso da nova sintaxe da lista de inicialização - que evita conversões silenciosas de estreitamento e acomoda a inicialização de membros com uma sintaxe uniforme - como um bom hábito para entrar. Seis de um, meia dúzia do outro?
Eljay
8
@nmr Não é seguro porque você pode perder o que está Deleterarmazenado dentro dounique_ptr
Zang MingJie