J'essaie d'utiliser un unique_ptr
à une classe dérivée dans une fonction qui prend un unique_ptr
à une classe de base. Quelque chose comme:
class Base {};
class Derived : public Base {};
void f(unique_ptr<Base> const &base) {}
…
unique_ptr<Derived> derived = unique_ptr<Derived>(new Derived);
f(derived);
Si je comprends bien cette réponse , ce code devrait fonctionner, mais il provoque les erreurs de compilation suivantes:
erreur C2664: 'f': impossible de convertir le paramètre 1 de 'std :: unique_ptr <_Ty>' en 'const std :: unique_ptr <_Ty> &'
IntelliSense: aucune conversion définie par l'utilisateur appropriée de "std :: unique_ptr <Derived, std :: default_delete <Derived>>" vers "const std :: unique_ptr <Base, std :: default_delete <Base>>" n'existe pas
Si je change f
pour prendre unique_ptr<Derived> const &derived
, ça marche bien, mais ce n'est pas ce que je veux.
Est-ce que je fais quelque chose de mal? Que puis-je faire pour contourner ce problème?
J'utilise Visual Studio 2012.
Vous avez trois options:
Renoncez à la propriété. Cela laissera votre variable locale sans accès à l'objet dynamique après l'appel de fonction; l'objet a été transféré à l'appelé:
f(std::move(derived));
Modifiez la signature de f
:
void f(std::unique_ptr<Derived> const &);
Modifiez le type de votre variable:
std::unique_ptr<base> derived = std::unique_ptr<Derived>(new Derived);
Ou bien sûr juste:
std::unique_ptr<base> derived(new Derived);
Ou même:
std::unique_ptr<base> derived = std::make_unique<Derived>();
pdate: Ou, comme recommandé dans les commentaires, ne transférez pas du tout la propriété:
void f(Base & b);
f(*derived);
Une solution possible consiste à changer le type de l'argument pour qu'il soit un Base const*
, Et à passer à la place derived.get()
. Il n'y a pas de transfert de propriété avec unique_ptr const<Base>&
(Et le unique_ptr
N'est pas modifié), donc le passage à un Base const*
Ne change pas la signification.
Herb Sutter discute longuement des arguments du pointeur intelligent dans Paramètres du pointeur intelligent . Un extrait de l'article lié fait référence à cette situation exacte:
Passer un
const unique_ptr<widget>&
Est étrange car il ne peut accepter quenull
ouwidget
dont la durée de vie est gérée dans le code appelant via ununique_ptr
, Et l'appelé ne devrait généralement pas se soucier du choix de gestion à vie de l'appelant. La réussite dewidget*
Couvre un sur-ensemble strict de ces cas et peut accepter "null
ouwidget
" quelle que soit la politique de durée de vie que l'appelant utilise.
J'avais l'option # 1 de la réponse acceptée et j'avais toujours la même erreur de compilation. Je me suis cogné la tête contre le mur pendant plus d'une heure et j'ai finalement réalisé que j'avais
class Derived : Base {};
au lieu de
class Derived : public Base {};