7
votes

Quelle est la bonne façon de convertir un std :: unique_ptr vers un std :: unique_ptr à une superclasse?

Supposons que j'ai une classe appelée foo qui hérite d'une classe appelée bar .

J'ai un std :: unique_ptr à une instance de foo et je veux le transmettre à une fonction ne prend que std :: unique_ptr . Comment puis-je convertir le pointeur afin qu'il fonctionne dans ma fonction?


4 commentaires

Est foo une instance polymorphe?


Faites des fonctions qui ne se préoccupent pas de l'emplacement de la mémoire ou de ce qui se passe ensuite, prenez les paramètres par référence (ou un pointeur brut si cela peut être null).


@Neilkirk: Ce travail de fonction, mais c'est un cas d'utilisation raisonnable pour stocker unique_ptr dans une collection. Et si la fonction doit le stocker ...


unique_ptr n'a pas de constructeur de copie, donc une fonction f (std :: unique_prt p) ne peut pas être appelé sans std :: Déplacer . Peut-être que vous vouliez dire que votre fonction prend une référence de rvalue ou de lvalue?


4 Réponses :


-1
votes

Vous ne pouvez pas, car cela violerait la règle la plus fondamentale unique_ptr : il ne doit y avoir qu'une seule instance qui contient un pointeur donné et le unique_ptr la propriété de celui-ci (quand il est hors de portée, le pointe est supprimé).

unique_ptr et unique_ptr (où u: t ) n'est pas compatible, comme vous l'avez vu.

pour Shared_ptr , pour lequel vous pouvez avoir plusieurs instances, il y a std :: static_pointer_cast qui se comporte comme un static_cast , sauf que Il accepte un partagé_ptr et renvoie un autre (et le point sur le même objet).

Si vous avez absolument besoin d'utiliser un unique_ptr , vous devez créer une fonction qui désresse d'abord votre de votre unique_ptr et met ce pointeur dans un nouveau type de droite. Vous pourriez également avoir besoin de la conversion opposée après l'appel de votre fonction.


14 commentaires

+1. Pour la complétude, std :: dynamic_pointer_cast <> et std :: const_pointer_cast <> existe pour d'autres conversions de pointeur communes.


Bien sûr que vous pouvez, vous devez simplement transférer la propriété, évidemment.


@Matthieuum. "Si vous avez absolument besoin d'utiliser un article_ptr, vous devrez créer une fonction qui déstabilise d'abord votre unique_ptr et met ce pointeur dans un nouveau type de droite." Mon point était qu'un unique_ptr ne peut pas se lier à un référence_ptr référence. Transférer la propriété comme ça n'est pas non plus exceptionnel.


@zneak: Comme quoi? base.Reset (dérivé.Release (Releasease ()) est une exception-coffre-fort (à part VS ...), base = std :: mouvement (dérivé) est une exception-sécurité aussi (et plus idiomatique). Et je ne vois pas vraiment pourquoi vous créeriez une fonction pour le faire car il est si court pour écrire.


@Matthieuum. Ce n'est pas une exception en sécurité si vous devez renvoyer le pointeur sur l'objet d'origine afin qu'il vit sa durée de vie correcte; et je crois qu'il n'y a pas de garantie que cela sera possible, car cet objet a été déplacé dans un autre et qu'il n'est pas nécessaire de faire quoi que ce soit, sauf être destructible à ce stade (bien que cela pratiquait cela fonctionnerait probablement, mais l'opération ne serait toujours pas possible. exception-coffre-fort si la callee jeté).


@zneak: J'ai lu votre commentaire deux fois et je crains de ne pas toujours comprendre ce que vous essayez de dire: '(Si vous pouviez m'aider avec un code d'exemple illustrant la question, je serais reconnaissant.


@zneak: Le commentaire est faux, la principale a éventuellement abandonné sa propriété lorsqu'elle l'a transmise par référence. Cela pourrait se produire avec quoi que ce soit, cela pourrait même se produire avec un pointeur adopté par référence. Une fois que vous passez quelque chose par référence, vous ne pouvez pas supposer que son état n'a pas changé. Je ne vois pas ce qui est particulièrement capable de transférer la propriété ici. Guide de style Google affirme que c'est la raison pour laquelle vous devriez toujours réussir par le pointeur (pour le rendre un peu plus évident sur le site d'appel), mais c'est comme ça dans presque tous chaque langue qui embrasse la mutabilité ....


@Matthieuum. Je ne dis pas que c'est techniquement impossible (il n'est clairement pas). Je dis que ce n'est pas une exception en sécurité. J'espère que le commentaire n'a pas obscuré cela.


@zneak: Et je suis en désaccord, bien que ce soit une question de qualification. unique_ptr fournit la garantie d'exception de base , même pour le transfert de propriété, et donc une exception-sécurité. Que le code vous conçu ne fournit pas la garantie d'exception forte (comme il semble que vous le souhaitez) est un problème avec votre code.


@zneak "Une fonction qui désresse d'abord votre ... etc" ... Vous voulez dire comme le unique_ptr bouger-constructeur? Qui est une partie centrale de ce qui fait unique_ptr utile? Toute cette réponse sonne comme si vous ne comprenez pas réellement unique_ptr .


En outre, "mon point était qu'un unique_ptr ne peut pas se lier à un unique_ptr référence." - D'accord, mais la question initiale est pas mention des références.


@Kylestrand, il n'y a pas d'exemple de code nulle part et interprétation est à jour en train de lire. Les conversions de valeur gardent généralement l'intacte d'origine, mais ce n'est pas le cas avec un document unique_ptr.


@zneak Votre réponse est la seule qui a supposé une interprétation qui (dans vos propres mots) "violerait la règle la plus fondamentale de unique." C'est à peine "la lecture de l'esprit" de préférer une interprétation raisonnable à une non-personne.


@Kytrand, que espérez-vous obtenir de cet échange?



27
votes

Vous pouvez convertir un std :: unique_ptr rvalue vers un std :: unique_ptr : xxx

Évidemment, le pointeur appartiendra par B et si b est détruit bar doit avoir un virtuel destructeur.


0 commentaires

0
votes

Vous pouvez utiliser cette syntaxe: xxx pré>

ou vous pouvez utiliser std :: déplacer code>. p>

L'autre option consiste à émettre de l'autre Pointeur, mais vous devez modifier une fonction: P>

void func(const parent* ptr)
{
  // actions...
}
func(*childptr);


0 commentaires

2
votes

Rien de spécial n'est requis en raison de l'héritage. Vous devez utiliser std :: Déplacer code> pour transmettre l'unique_ptr à une fonction, mais ceci est vrai même si les types correspondent à:

#include <memory>

struct A {
};

struct B : A {
};

static void f(std::unique_ptr<A>)
{
}

int main(int,char**)
{
  std::unique_ptr<B> b_ptr(new B);
  f(std::move(b_ptr));
}


0 commentaires