Avec des pointeurs normaux, je peux faire quelque chose comme ce qui suit
ptr = std::move(conditional_reassign2(std::move(ptr)));
Et je peux passer le pointeur que je veux changer comme suit
ptr = conditional_reassign2(std::move(ptr));
Je souhaite réimplémenter cela avec std :: unique_ptr
. Voici ce que j'ai trouvé
std::unique_ptr<MyClass> ptr = make_unique<MyClass>(old_param); ptr = std::move(conditional_reassign2(std::move(ptr)));
Et je l'appellerais avec la
std::unique_ptr<MyClass> conditional_reassign2(std::unique_ptr<MyClass> ptr) { if (my_condition) { ptr = std::make_unique<MyClass>(new_param); } return std::move(ptr); }
Je ne suis pas tout à fait satisfait de la verbosité de la ligne
MyClass* ptr = new MyClass(old_param); conditional_reassign(ptr);
Y a-t-il un moyen d'implémenter conditional_reassign2
afin que je puisse l'appeler dans d'une manière similaire à conditional_reassign(ptr)
Je devrais noter un problème majeur avec
void conditional_reassign(MyClass* ptr) { if (my_condition) { delete ptr; ptr = new MyClass(new_param); } }
est qu'il détruira l'objet d'origine ptr
pointé indépendamment de my_condition
(voir Pourquoi la réaffectation d'un pointeur intelligent à lui-même provoque-t-elle une destruction? )
3 Réponses :
Vous pouvez définir la fonction De cette façon, la fonction peut directement modifier l'instance qui est transmise, pas besoin de transférer la propriété. En supposant que conditional_reassign2 ()
pour prendre std :: unique_ptr
par référence au lieu de par valeur em>: conditional_reassign2(ptr);
ptr code> est un
std::unique_ptr
, alors appeler conditional_reassign2 ()
serait dans ce cas: void conditional_reassign2(std::unique_ptr<MyClass>& ptr)
{
if (my_condition)
{
ptr = std::make_unique<MyClass>(new_param);
}
}
Soit vous devez passer le pointeur par la référence
std::unique_ptr<MyClass> conditional_reassign2(std::unique_ptr<MyClass> ptr) { if (my_condition) ptr = std::make_unique<MyClass>(new_param); return ptr; }
, soit retourner le pointeur, ce qui nécessite un seul déplacement
std::unique_ptr<MyClass> conditional_reassign2(std::unique_ptr<MyClass> ptr) {...} std::unique_ptr<MyClass> myPtr; myPtr = conditional_reassign2(std::move(myPtr));
Vous aussi peut renvoyer ptr directement depuis la fonction sans appeler explicitement move.
void conditional_reassign2(std::unique_ptr<MyClass>& ptr) {...} std::unique_ptr<MyClass> myPtr; conditional_reassign2(myPtr);
Votre premier exemple ne fait pas ce que vous avez l'intention de faire. Comme ptr
est passé par valeur, le pointeur de l'appelant ne sera pas modifié. Donc, si my_condition
est true
, l'appelant a un pointeur qui pointe vers un objet supprimé, et l'adresse à laquelle l'objet nouvellement créé est stocké est perdue après le retour de la fonction .
Voici votre premier exemple corrigé (l'argument est maintenant une référence à un pointeur):
std::unique_ptr<MyClass> ptr = make_unique<MyClass>(old_param); ptr = conditional_reassign2(std::move(ptr));
Pour utiliser unique_ptr, vous pouvez également utiliser des références et ne rien renvoyer . De cette façon, pas besoin de traiter std::move
std::unique_ptr<MyClass> conditional_reassign(std::unique_ptr<MyClass> ptr) { if (my_condition) { return std::make_unique<MyClass>(new_param); } return ptr; }
Vous pouvez l'appeler comme ceci:
std::unique_ptr<MyClass> ptr = make_unique<MyClass>(old_param); conditional_reassign2(ptr);
Toutes mes excuses si j'ai mal interprété votre question, mais
conditional_reassign
ne fait pas ce que vous semblez penser. Cela ne change pas leptr
de l'appelant. Pour cela, vous devez le passer par référence ou faire en sorte que la fonction prenne un pointeur vers un pointeur.Le std :: move externe est redondant.
Pourquoi utilisez-vous le même ptr pour la valeur de retour et comme paramètre?
Votre fonction
conditional_reassign ()
(comme indiqué) entraîne un comportement indéfini et est un excellent exemple de la raison pour laquelle vous devriez convertir votre code pour utiliserunique_ptr
. Votre bug actuel est bien plus difficile à implémenter avecunique_ptr
:-)