2017-06-11 1 views
0

Je dois créer un opérateur + pour ma classe, je l'ai fait comme ceci:Comment libérer la valeur retournée correctement

class CDoubleString{ 
public: 
    string textA=""; 
    string textB=""; 
    CDoubleString(string x,string y) : textA(x),textB(y){} 

    CDoubleString & operator + (const CDoubleString & y){ 
     CDoubleString * n=new CDoubleString(textA,textB); 
     n->textA+=y.textA; 
     n->textB+=y.textB; 
     delete n; 
     return *n; 
    } 
} 

Il semble qu'il fonctionne comme prévu, mais je vois qu'il ya un problème avec libérer la mémoire. Au moment où je l'ai retourné, ça peut déjà être autre chose. Donc, c'est un comportement indéfini, ai-je raison?
Comment éviter cela?

+3

Je recommande [cette référence] (http://en.cppreference.com/w/cpp/language/operators#Canonical_implementations) sur les implémentations canoniques des opérateurs surchargées. Plus précisément la [section sur les opérateurs binaires] (http://en.cppreference.com/w/cpp/language/operators#Binary_arithmetic_operators). Notez la différence de la valeur renvoyée par rapport à votre code. –

+0

@Someprogrammerdude Je connais effectivement cette référence et l'utilise de temps en temps, mais je ne connaissais pas cette section. Merci. – TGar

Répondre

3

Donc, c'est un comportement indéfini, ai-je raison?

Oui.

Comment éviter cela?

Il existe plusieurs façons.

  1. Retour en valeur

    CDoubleString operator + (const CDoubleString & y){ 
        CDoubleString n(textA,textB); 
        n.textA+=y.textA; 
        n.textB+=y.textB; 
        return n; 
    } 
    
  2. Retour un std::unique_ptr

    std::unique_ptr<CDoubleString> operator + (const CDoubleString & y){ 
        std::unique_ptr<CDoubleString> n = std::make_unique<CDoubleString>(textA,textB); 
        n->textA+=y.textA; 
        n->textB+=y.textB; 
        return n; 
    } 
    

je préférerais la 1ère variante pour votre cas. Vous pouvez compter sur RVO et copyelistion pour la plupart des compilateurs modernes, vous n'avez donc pas besoin de vous soucier de copies supplémentaires.

1

Donc, c'est un comportement non défini, ai-je raison?

Oui, mais pas tout à fait pour la raison que vous en pensez. Vous renvoyez une référence à un objet déjà supprimé, et cela est invalide et a un comportement indéfini. Mais le "ça peut être quelque chose d'autre" s'applique à l'appelant, parce que c'est l'appelant qui finirait par lire cette référence morte, et cela pourrait causer des problèmes même si vous deviez retarder la suppression de l'objet: vous pourrait encore ne pas le retarder assez.

Comment éviter cela?

Le retour en valeur est probablement le plus facile.

CDoubleString operator + (const CDoubleString & y){ 
    CDoubleString n(textA,textB); 
    n.textA+=y.textA; 
    n.textB+=y.textB; 
    return n; 
}