2009-12-21 5 views
4

J'expérimente avec la suppression d'opérateur de surcharge, de sorte que je puisse retourner un pointeur simple à ceux qui ne souhaitent pas travailler avec des pointeurs futés, et être capable de contrôler quand l'objet est supprimé.opérateur de surcharge supprimer, ou comment tuer un chat?

Je définis une classe Cat qui est construite avec plusieurs âmes, a une suppression d'opérateur surchargée qui ne fait rien, et un destructeur qui décrémente le nombre d'âmes (et fait aussi quelques vantardises). Quand les âmes atteignent 0, le destructeur appelle le global :: delete, et le chat meurt.

Cela semble assez simple, mais ne fonctionne pas comme prévu. Voici le code:

class Cat { 
public: 
    Cat(string n): name(n), souls(9) 
    { cout << "Myaou... " << name << " is born\n"; } 

    ~Cat(); 
    void operator delete(void *p) { cout << "!!! operator delete called\n"; } 
    void report() 
    { cout << name << "'s here, " << souls << " souls to spend\n"; } 

    friend ostream& operator<< (const ostream& o, const Cat& cat); 
private: 
    void kill(); 
    const string name; 
    int souls; 
}; 

Cat::~Cat() 
{ 
    cout << "!!! dtor called\n"; 
    kill(); 
} 

void Cat::kill() 
{ 
    if (--souls) 
     cout << name << " is still alive! I have " << souls << " souls left.\n"; 
    else { 
     cout << name << " is dying... good bye world!\n"; 
     ::delete((void*)this); 
    } 
} 

ostream& operator<< (const ostream& o, const Cat& cat) 
{ 
    return o << cat.name << "'s here, " << cat.souls << " souls to spend\n"; 
} 

est ici le principal:

int main() 
{ 
    Cat *p = new Cat("Mitzi"); 

    for (;;) 
    { 
     char c[100]; 
//  cout << *p; 
     p->report(); 
     cout << "come on, hit me!"; 
     cin >> c; 
     delete p; 
    } 
} 

Je pense que la boucle courrait pour 9 fois, puis quelque chose de désagréable (accident) se passerait-il. Cependant, ceci est la sortie:

Myaou... Mitzi is born 
Mitzi's here, 9 souls to spend 
come on, hit me!c 
!!! dtor called 
Mitzi is still alive! I have 8 souls left. 
!!! operator delete called 
's here, 8 souls to spend 
come on, hit me!c 
!!! dtor called 
is still alive! I have 7 souls left. 
*** glibc detected *** /home/davidk/workspace/string_test/Debug/string_test: double free or corruption (fasttop): 0x080cd008 *** 

Paraît que, après la première supprimer le membre de nom est détruit, et la prochaine suppression provoque un accident. Des explications? Je compile avec gcc sur Linux, peut être un bug de compilateur?

BTW, quand je l'opérateur < <() comme dans Cout < < * p au lieu de repotr(), il était aussi bizarre: il est entré dans une boucle infinie d'appeler le constructeur à partir de l'opérateur < <() . Que se passe t-il ici? :)

merci!

+0

hey, tirer CMyFoot mais pas le pauvre chat! –

Répondre

7

L'opérateur delete appelle le destructeur d'objet et après que vous n'êtes dans aucun no man's land. Comme d'autres l'ont souligné, ce que vous essayez de faire n'est pas possible. Ce que vous faites est également un peu douteux en termes de comportement incohérent lorsque l'objet est construit sur le tas et sur la pile.Avec votre idée de surcharger l'opérateur delete l'objet restera vivant selon une logique interne (le nombre de vies a atteint 9) si construit en utilisant nouveau.

Lorsque construit sur la pile (Cat cat("Chesire cat");) l'objet va toujours être détruit quand il sort de la portée. Afin de réaliser ce que vous essayez de faire, vous devrez également changer le comportement du destructeur pour "arrêter la destruction". Ce n'est pas possible, même pour de très bonnes raisons. Donc, si vous voulez compter les références, mettez en place votre propre mécanisme. Après tout, vous ne pouvez pas vous appeler un programmeur C++ si vous n'avez pas fait votre propre gestion de la mémoire de compte ref au moins une fois :))

+0

C'est un bon point, merci, mais comme je l'ai dit, j'expérimentais, donc je voulais surtout jouer avec delete et voir comment ça marche. J'aurais pu compléter ceci avec un nouvel opérateur surchargé qui placerait un certain drapeau que l'objet a été créé sur le tas, par exemple. Personnellement, j'aurais utilisé shared_ptr plutôt que de le ré-implémenter. – davka

+0

Je peux voir la raison pour ne pas surcharger 'delete', mais existe-t-il un autre moyen d'empêcher l'utilisateur d'appeler delete sur un pointeur intelligent? J'écris ma propre gestion de mémoire de comptage de ref et cela fonctionne très bien ... tant que l'utilisateur laisse tomber le pointeur de la pile ou appelle 'smartPtr-> ReleaseReference()'. Si l'utilisateur essaie de 'supprimer smartPtr' alors que 'smartPtr-> refCount'> 1, il me reste des SmartPointers pendants qui causent des problèmes quand * ceux-ci * sont finalement détruits (parce qu'ils font référence à des blocs désalloués). – cjcurrie

1

Le destructeur n'est pas responsable de la libération de la mémoire et ne l'a pas empêché de se produire.

Le premier appel libère la mémoire, le deuxième appel se déclenche.

+7

première fois que j'ai vu "u've". J'espère que c'est la dernière;) – pavium

+0

Abréviations sans être grammaticalement correct. Je pensais que cela serait vu sous un jour positif ici :). – Dynite

+0

l'opérateur surchargé devrait avoir empêché, et semble qu'il a fait, c'est le membre qui est allé kaput, comme les gens me disent ici. – davka

2

Une fois que le destructeur d'un objet a été appelé, tout ce que vous faites avec l'objet n'est pas défini. Ce que vous essayez de faire n'est pas possible.

19

Vous avez abusé de tous les concepts C++ possibles et cela provoque des erreurs. Lorsque delete p; est appelé pour la première fois C++ appelle le destructeur Cat::~Cat() qui détruit implicitement le std::string à l'intérieur de l'entité. Lorsque delete p; est appelé la deuxième fois Cat::~Cat() est réexécuté et il réexécute le destructeur du std::string et cela provoque un comportement indéfini qui bloque le programme car je suppose que std::string::~string() n'annule pas le pointeur vers le tampon et lorsque std::string::~string() essaie de libérer le tampon pour le deuxième fois avec la même adresse cela conduit à fameux double-libre.

+0

Oui, manqué le destructeur de la chaîne std ::, correct. Merci! – davka

+4

Chaque concept C++ possible, hein? – cjcurrie

1

Vous devez savoir que vous ne pouvez pas effectuer une suppression sur une même adresse plusieurs fois.