2010-07-23 13 views
1

I ont la classe suivante:Suppression d'une structure imbriquée avec des pointeurs void en tant que membres?

class Stack { 
    struct Link { 
    void* data; 
    Link* next; 
    void initialize(void* dat, Link* nxt); 
    }* head; 
public: 
    void initialize(); 
    void push(void* dat); 
    void* peek(); 
    void* pop(); 
    void cleanup(); 
}; 

La méthode pop est:

void* Stack::pop() { 
    if(head == 0) return 0; 
    void* result = head->data; 
    Link* oldHead = head; 
    head = head->next; 
    delete oldHead; 
    return result; 
} 

oldHead est un pointeur vers une struct Link, qui a un pointeur nul en tant que membre. Donc, en supprimant oldHead, je supprime implicitement ce pointeur vide, non? Je suis en train de lire Thinking in C++ de Bruce Eckel, et il dit que la suppression des pointeurs vides ne nettoie pas les choses correctement car delete a besoin de connaître le type du pointeur.

Ce code supprime implicitement le pointeur vide data, donc: Quelqu'un peut-il expliquer pourquoi cette façon (implicite) de supprimer un pointeur vide est différente de la suppression avec delete <void pointer>? En supprimant Link, cet espace mémoire vide * n'est pas supprimé.

+0

Pourquoi pensez-vous que c'est différent? –

+2

En ce qui concerne la réflexion en C++, n'utilisez pas void *. Les modèles fonctionneraient parfaitement pour cet exemple. –

+0

David, j'ai supposé que c'était différent puisque l'auteur d'abord met en garde contre l'utilisation de supprimer sur les pointeurs de vide, puis utilise le code ci-dessus. –

Répondre

2

Votre terminologie est ambiguë, mais laissez-moi vous expliquer. Disons que vous avez:

struct foo 
{ 
    void* bar; 
}; 

Chaque fois qu'un foo termine sa durée de vie, bar arrête simplement existant aussi. Donc, si vous avez:

{ 
    foo f = { new int; } 
} 

Vous avez eu une fuite, comme new int est jamais supprimé.De même, quand vous faites:

{ 
    foo* f = new foo; 
    f->bar = new int; 
    delete f; 
} 

Vous avez toujours eu une fuite, depuis quand delete f est exécuté, vous finissez simplement la durée de vie de ce f pointe vers (comme ce qui est arrivé automatiquement au-dessus), ergo bar cesse simplement existe et le new int n'est pas supprimé.

Pour résumer, lorsque la durée de vie d'un objet se termine, delete est et non appelé sur les membres qui sont un pointeur.

Ainsi, lorsque vous appelez supprimer sur un Link, il est la même situation que dans barfoo ci-dessus: vous deleteing la mémoire pour un Link provoquant data d'arrêter existant, mais pas supprimer réellement ce qu'il pointant.

+0

Merci à tous pour vos réponses. –

0

Vous devez définir un destructeur qui supprime la mémoire qui a été allouée. Chaque nouvelle nécessite une suppression. Un exemple de ceci pour la structure de lien serait d'ajouter un destructeur qui supprime data. Si votre hypothèse est correcte, alors next sera également supprimé, entraînant la suppression de l'ensemble de votre liste de liens, ce qui serait un comportement terrible. Appeler la suppression sur un pointeur appellera le destructeur du type pointé vers

Si ce type n'a pas de destructeur, aucun destructeur de ce type ne sera appelé. C'est le cas pour un pointeur vide qui n'a pas de destructeur. Dans le cas de l'héritage, le destructeur doit toujours être virtuel de sorte que la classe la plus profonde de la hiérarchie ait son destructeur appelé. La mémoire sera correctement libérée même si vous jetez vos pointeurs vers les mauvais types - c'est juste que le destructeur sera appelé incorrectement.

0

"Je supprime implicitement ce pointeur vide, n'est-ce pas?"

Eh bien, vous supprimez le pointeur lui-même lorsque vous supprimez oldHead. Vous ne supprimez pas ou ne libérez pas son cible, ce qui est ce que vous semblez vouloir, et est ce qui se passe lorsque vous appelez delete sur un pointeur.

(Pour voir pourquoi il en est le cas, considérez que vous pouvez définir une struct avec Vous ne voudriez pas le pointeur void* qui pointe vers quelque chose en dehors du struct. La cible à libérer juste parce que la structure a été supprimée.)

+0

Il retourne la cible, donc il ne devrait pas le supprimer en premier lieu. En raison des pointeurs vides, la classe de pile n'a aucune idée de ce qu'est la cible. La gestion des valeurs stockées dépend entièrement de l'utilisateur. (En C++, ces classes sont normalement écrites avec des modèles, et les pointeurs vides ne sont pas utilisés à moins qu'il y ait une très bonne raison - compatibilité avec le vieux code C et autres.) – UncleBens

0

Un problème avec la suppression d'un pointeur vide se produit lorsque vous pointez quelque chose avec un destructor:

#include <iostream> 

struct foo 
{ 
    ~foo() { std::cout << "important work" << std::endl; } 
}; 

int main() 
{ 
    foo *f = new foo; 

    void *v = f; 

    delete v; 
} 

Si vous exécutez l'exemple de code ci-dessus, vous verrez que le destructor est jamais appelé.