Est-ce que C ++ 11 unique_ptr et shared_ptr sont capables de se convertir dans le type de l'autre?

99

La bibliothèque standard C ++ 11 fournit-elle un utilitaire pour convertir de a std::shared_ptren std::unique_ptr, ou vice versa? Cette opération est-elle sûre?

Forsum postérieur
la source
Veuillez définir «fonctionnement sûr». Quel type de sécurité recherchez-vous? gestion de la sécurité à vie? Sécurité des fils?
jaggedSpire
2
"STL" ne signifie pas bibliothèque standard. La STL n'a rien à voir avec shared_ptr.
curiousguy
1
@jaggedSpire La sécurité des threads signifierait que vous avez des propriétaires utilisés dans différents threads, c'est-à-dire que le nombre d'utilisation n'est pas de 1.
curiousguy
@curiousguy je le savais. Mon argument était que la «sécurité» n'était pas bien définie dans la question de l'OP, et il avait besoin de clarifier de quel type de «sécurité» il parlait, car il en existe plusieurs.
jaggedSpire

Réponses:

161

std::unique_ptrest le moyen C ++ 11 d'exprimer la propriété exclusive, mais l'une de ses fonctionnalités les plus attrayantes est qu'il se convertit facilement et efficacement en un fichier std::shared_ptr.

C'est un élément clé de la raison std::unique_ptrpour laquelle il convient si bien qu'un type de retour de fonction d'usine. Les fonctions d'usine ne peuvent pas savoir si les appelants voudront utiliser la sémantique de propriété exclusive pour l'objet qu'ils retournent ou si la propriété partagée (c'est-à-dire std::shared_ptr) serait plus appropriée. En renvoyant un std::unique_ptr, les usines fournissent aux appelants le pointeur intelligent le plus efficace, mais ils n'empêchent pas les appelants de le remplacer par son frère plus flexible.

std::shared_ptrà std::unique_ptrn'est pas autorisé. Une fois que vous avez transformé la gestion à vie d'une ressource en a std::shared_ptr, vous ne pouvez plus changer d'avis. Même si le nombre de références est égal à un, vous ne pouvez pas récupérer la propriété de la ressource pour, par exemple, la std::unique_ptrgérer.

Référence: C ++ moderne efficace. 42 MANIÈRES SPÉCIFIQUES D'AMÉLIORER VOTRE UTILISATION DE C ++ 11 ET C ++ 14. Scott Meyers.

En bref, vous pouvez facilement et efficacement convertir un std::unique_ptren std::shared_ptrmais vous ne pouvez pas le convertir std::shared_ptren std::unique_ptr.

Par exemple:

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
la source
9
...Comment faites-vous?
Jake
4
@Jake J'ai ajouté un exemple
chema989
Sachez que même s'il n'est pas autorisé, le compilateur (du moins pas gcc) n'empêchera pas (ou même avertira) si vous affectez accidentellement (par exemple en changeant le type de pointeur d'une variable membre) a std::unique_ptrà a std::shared_ptr.
StefanQ
-8

Étant donné unique_ptr u_ptr, créez shared_ptr s_ptr:

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

Il n'est pas pratique d'aller dans l'autre sens.

RMN
la source
29
Voici la "bonne" façon:std::shared_ptr<whatever> s_ptr(std::move(u_ptr));
emlai
6
Et voici la "bonne" voie pédante:std::shared_ptr<whatever> s_ptr{std::move(u_ptr)};
polyvertex
3
Qu'est-ce qui est moins sûr à ce sujet?
nmr
7
@VioletGiraffe • Je suppose que polyvertex préconise l'utilisation de la nouvelle syntaxe de liste d'initialisation - qui évite les conversions réductrices silencieuses et permet l'initialisation des membres avec une syntaxe uniforme - comme une bonne habitude à prendre. Six d'un, une demi-douzaine de l'autre?
Eljay
8
@nmr C'est dangereux car vous risquez de perdre le Deleterstocké à l'intérieur duunique_ptr
Zang MingJie