1
votes

Réattribuer un pointeur intelligent dans une fonction sans en transmettre la propriété?

Contexte

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);
}

Question

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)

Edit

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? )


4 commentaires

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 le ptr 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 utiliser unique_ptr . Votre bug actuel est bien plus difficile à implémenter avec unique_ptr :-)


3 Réponses :


1
votes

Vous pouvez définir la fonction conditional_reassign2 () pour prendre std :: unique_ptr par référence au lieu de par valeur em>:

conditional_reassign2(ptr);

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 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);
    }
}


0 commentaires

3
votes

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);


0 commentaires

0
votes

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);


0 commentaires