2016-08-18 2 views
1

Je suis un peu confus, car j'étais sûr que cela devrait fonctionner différemment. Jetez un oeil à cet exemple de code:Objet non supprimé avant que le nouveau soit affecté

#include <iostream> 
#include <string> 

using namespace std; 

class base 
{ 
    public: 
    virtual ~base() = default; 
}; 

class derived : public base 
{ 
    private: 
    int a = 0; 
    int *b = nullptr; 
    std::string lol; 

    public: 
    derived(std::string s) : b(new int(6)), lol{s} { cout << "ctor " << lol << endl; } 
    derived(derived const& d) : lol{d.lol + " copy"} {cout << "copy " << lol << endl; } 

    virtual ~derived() { cout << "dtor " << lol << endl; delete b; } 

    virtual void superFunction() { cout << "OMG " << lol << endl; } 
}; 

int main() 
{ 
    derived a("a"); 
    derived b("b"); 
    a = b; 
} 

Et la sortie du programme avec toutes les optimisations au large est:

ctor a 
ctor b 
dtor b 
dtor b 

Je suis sûr que dans ce compilateur cas devrait générer un code qui supprime l'objet a et utilise copie constructeur pour créer un nouvel objet. Au lieu de cela, il utilise operator= qu'il déclare implicitement.

Quelqu'un peut-il expliquer pourquoi? Ou pointez-moi à la norme C++.

Merci.

+1

Si « le compilateur » supprime 'd'abord a', quel serait-il copier dans' b'? De toute façon, il n'y a pas de copie ici, juste une cession. – juanchopanza

+0

en rapport: https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three – vu1p3n0x

Répondre

5

Lorsque vous écrivez a = b;, l'opérateur d'affectation des appels du compilateur est automatiquement généré s'il n'est pas présent dans le code et n'est pas marqué comme supprimé. Copie constructeur est utilisé que si vous essayez de initialize un nouvel objet d'un autre objet comme celui-ci:

derived a("a"); 
derived b = a; 

En outre, plantage de votre code avant principal reparaît comme il essaie de supprimer b, qui pointe vers la même mémoire de a et b après a = b; par défaut.

Si vous voulez supprimer a avec derived destructeur après l'exécution a = b;, tout ce dont vous avez besoin est idiome copier-et-swap. What is the copy and swap idiom? a une excellente réponse sur la façon de le faire dans l'héritage et le C++ moderne. Une implémentation correcte de la règle de quatre à partir de cette réponse s'adaptera parfaitement au principe DRY et vous aidera à éviter les problèmes de mémoire. Notez le truc fabuleux avec le passage de paramètres à operator=par la valeur, ce qui rend le compilateur sélectionner le constructeur approprié (copier ou déplacer) et vous permet d'écrire seulement quatre méthodes au lieu de tous five d'entre eux.