2010-03-02 6 views
3

J'ai des problèmes pour utiliser ma classe personnalisée avec une carte std :: map. La classe alloue dynamiquement de la mémoire pour les membres, et je ne veux pas utiliser de pointeur dans la map car je veux m'assurer que la classe s'occupe de supprimer toute la mémoire allouée. Mais le problème que j'ai est après avoir ajouté un élément à la carte, quand ce bloc de code sort de sa portée, le destructeur d'objets est appelé même s'il est toujours sur la carte. J'ai fait un faux code ci-dessous qui montre ce que je veux dire. La sortie est: Alors le problème est pourquoi le destructeur final est-il appelé? Merci d'avance et désolé pour la longue question.Pourquoi le constructeur de copie n'est-il pas appelé comme je l'espère ici en utilisant map?

Constructor Called Num:0034B7E8 
Default Constructor Called Num:00000000 
Copy Constructor Called Num:CCCCCCCC 
Copy Constructor Called Num:CDCDCDCD 
destructor called Num:CCCCCCCC 
destructor called Num:00000000 
destructor called Num:0034B7E8 
Inserted Num:0034B7E8 



class myClass 
{ 
public: 
    myClass(int num) 
    { 
    mnNum = new int(); 
    cout << "Constructor Called Num:" << mnNum << endl; 
    } 

    myClass() : mnNum(NULL) 
    { 
     cout << "Default Constructor Called Num:" << mnNum << endl; 
    } 

    myClass(const myClass &copy) 
    { 
     mnNum = new int(copy.mnNum); 
     cout << "Copy Constructor Called Num:" << mnNum << endl; 
    } 

    ~myClass() 
    { 
     delete mnNum; 
     mnNum = NULL; 
    } 

    int* mnNum; 

}; 

map<string,myClass> mvMyMap; 

void testFunction() 
{ 
    myClass lcObj(1); 

    mvMyMap["Test"] = lcObj; 
} 


int _tmain(int argc, _TCHAR* argv[]) 
{ 
    testFunction(); 
    cout << "Inserted Num:" << mvMyMap["Test"].mnNum << endl; 
return 0; 
    } 
+1

Plase, code post-réel. Votre code actuel est faux. Il ne compilera pas au moins à l'instruction 'mnNum = new int (copy.mnNum)'. – AnT

Répondre

10

myClass nécessite un opérateur d'affectation personnalisé, en plus du constructeur de copie. Ainsi, lorsque vous effectuez une affectation, vous perdez la valeur d'origine sur la gauche, et finalement doublez la valeur sur la droite.

+0

Bonne prise. Vraiment, un pointeur intelligent est probablement le meilleur moyen d'aller ici. Cela peut signifier un pointeur intelligent dans la classe, ou simplement stocker un pointeur intelligent * vers * la classe, dans la carte. –

+0

Oui, j'ai oublié la règle de trois qui stipule que je devrais avoir un opérateur d'affectation lorsque j'ai un constructeur de copie et un destructeur. – CptanPanic

-1

Votre constructeur ignore le paramètre num et initialise jamais mnNum de lui. Il devrait ressembler à:

myClass(int num) 
{ 
    mnNum = new int(num); 
    cout << "Constructor Called Num:" << mnNum << endl; 
} 

Vous devez également ajuster votre constructeur de copie comme ceci:

myClass(const myClass &copy) 
{ 
    mnNum = new int(*copy.mnNum); 
    cout << "Copy Constructor Called Num:" << mnNum << endl; 
} 

modifier

Derek Ledbetter a souligné que nous avons besoin d'un opérateur d'affectation, aussi. Et je suggère de rendre le destructeur virtuel.

+2

Il n'est pas nécessaire de rendre le destructeur virtuel à moins qu'il ne s'agisse d'une classe de base polymorphe. Ce qui n'est pas. –

+0

@Mike, si vous n'autorisez pas l'héritage, alors je suis d'accord pour dire qu'il n'y a pas besoin d'un destructeur virtuel. Cependant, le code le permet actuellement. Si vous voulez omettre le virtuel alors je crois que vous devriez également modifier le code pour empêcher l'héritage. Il n'y a pas de «scellé», mais il existe des façons équivalentes de le faire. –

+2

La classe a une sémantique de valeur (c'est-à-dire qu'elle est copiable et assignable) et aucune fonction virtuelle, donc elle ne peut pas être utilisée comme une classe de base polymorphe. L'ajout d'un destructeur virtuel juste au cas où quelqu'un ferait quelque chose de bête ne fera que fausser le code erroné. –

Questions connexes