7
votes

Est-ce que ça va d'utiliser "Supprimer ceci" pour supprimer l'objet actuel?

J'écris une liste liée et je veux un destructeur d'une structure (une structure de nœud) pour simplement supprimer lui-même et ne pas avoir d'effets secondaires. Je veux que la destructeur de ma liste appelle itéhentifiant le destructeur de nœud sur lui-même (stocker temporairement le nœud suivant), comme celui-ci: xxx pré>

Ce serait donc mon noeud destructeur: P>

Node::~Node
{
   delete this;
}


1 commentaires

Je vais être le dernier qui ira à une rampage de fermeture mais je crois que cette question a été posée plusieurs fois dans le passé déjà: Google.com/Search?q=delete+This+SiteHsiteHstFlow.com


8 Réponses :


17
votes

Si le destructeur de nœud est appelé, il est déjà en cours d'être supprimé. Donc, une suppression n'a pas de sens à l'intérieur de votre nœud destructeur.

Ce est faux: xxx

à la place, vous devriez obtenir temp-> suivant () dans une variable TEMP . Sinon, vous accédez à la mémoire supprimée.

aussi comme ceci: xxx


8 commentaires

Remarque: puisque vous supprimez tous les nœuds de votre destructeur de DoubleLylinkedList, vous ne devez pas supprimer les objets de noeud ailleurs.


Ainsi, j'ai besoin d'un nœud destructeur du tout? Je ne veux tout simplement pas que le dttor fourni par le compilateur soit embrasé avec ma vie.


Vous pouvez en mettre un et le laisser vide ou vous ne pouvez pas le mettre un du tout.


@Hooked, le DTor fourni par le compilateur équivaut à juste écrire un dteur avec un corps vide. Il détruira les variables des membres et les superclasses, peu importe ce que vous faites - à ce moment-là, vous ne pouvez pas l'arrêter (à court de résilier le programme d'abord)


Donc, si je devais concevoir une classe sans mémoire allouée à un tas ala neuf, aurais-je besoin d'un constructeur ou serais-t-il supprimé quand il sort de la portée?


Si vous utilisez de nouveaux, vous devez utiliser Supprimer. Vous supprimez une fois par nouveau. Les constructeurs sont appelés s'il est appelé ou non. Ce sont des concepts indépendants. Les objets seront libérés lorsque le nouveau n'est pas utilisé lorsqu'ils sortent de la portée Oui. Mais pour une structure de données de liste liée, vous n'utiliseriez pas d'objets de pile.


De même, la mémoire allouée de tas, un nouveau ou un malloc attribué. Stack alloué signifie que vous n'avez pas affecté de manière dynamique la mémoire via NE NOR MALLOC.


J'espère bien. Je déteste penser que je lance des termes que je ne comprends pas.



0
votes

Le code ci-dessus appellera noeud :: ~ noeud () deux fois. (En "Supprimer Temp" et dans Node :: ~ Noeuds ())

nœud :: ~ nœud () ne doit pas appeler "Supprimer ceci" (ou votre programme s'écrasera)

ps. Alors que la boucle de votre code ne fonctionnera pas. Le pointeur invalide de la déréence sera un pointeur non valide. Vous devez d'abord copier la valeur de Temp-> Suivant, puis détruire le pointeur Temp.


1 commentaires

En réalité, nœud :: ~ noeud () ne sera pas appelé deux fois, mais finissez dans un débordement de pile (ha!) En raison de la récursion sans fin.



4
votes

Non, vous ne devriez pas Supprimer ce du destructeur. Le destructeur est appelé à cause d'une déclaration de suppression (ou est hors de portée) et cela conduirait probablement à une sorte de crash.

Vous avez également un couple de problèmes dans le DoubleLylinkedList DisturCtor. Un, vous supprimez Temp puis accédez à la température après que cela a été supprimé. Deuxièmement, le code ne supprimera pas réellement le dernier élément de la liste liée.


0 commentaires

1
votes

Supprimer ceci; appellerait le destructeur de l'objet actuel. Dans ce cas, si vous appelez, supprimez ceci; Dans le destructeur, alors le destructeur serait appelé infiniment jusqu'à l'accident.


0 commentaires

4
votes

Actuellement, votre code provoquerait une violation d'accès, car la deuxième des lignes suivantes accède clairement à la mémoire libérée: xxx

si vous souhaitez supprimer récursivement la structure, vous voulez quelque chose comme ça : xxx


6 commentaires

Un problème avec cette approche est que si vous souhaitez supprimer un nœud arbitraire, vous éliminez chaque nœud qui le suit.


Bon point, merci. Je veux éviter une mise en œuvre récursive car cela pourrait être inefficace pour les grandes listes, je crois.


Le code de l'OP ne provoquera pas nécessairement AV - la mémoire libérée peut être laissée accessible par le processus ou peut être renvoyée au système d'exploitation et devenir inaccessible - il appartient au gestionnaire de démarrage.


@harto: C'est facile à éviter par un suivant () avant de détruire ceci . (Si vous avez une liste doublement liée, cela semble plus propre de toute façon, car sinon suivant () -> prev () signalerait un nœud supprimé.)


@Hooked: Je mesurerais avant de dire ça. Avec des listes liées, la non-localité (si c'est un mot) est probablement la principale performance frappée. En plus de cela, la récursion vs. itération pourrait ne pas faire de différence du tout. IMHO L'approche récursive s'adapte naturellement et semble facilement compréhensible, alors auparavant, je devrais mesurer.


@Dimitry: votre si (this-> suivant ()! = Null) Supprimer ceci-> Suivant (); est inutilement verbeux. Il est correct de passer un "code> null sur Supprimer , donc supprimer ceci-> suivant (); suffira. En outre, DoublyLinkedList :: ~ DoublylinkedList () (en plus de manquant () ) pourrait être plus court, aussi, sans perdre (et peut-être même gagner) la lisibilité. Voir ma publication. :)



0
votes

En général, un destructor devrait juste se soucier de suppression-ment (ou libre-ment si vous utilisez C ou malloc) toute mémoire allouée spécifiquement pour votre objet. Suppression d'un pointeur vers votre objet sera toujours géré par le système d'exploitation et vous n'avez pas à vous soucier d'une chose au sujet de cette partie.

Une chose à garder à l'esprit est que, sur la construction, vous créez d'abord l'objet (comme le flux de contrôle pénètre dans le corps du constructeur), les objets à l'intérieur; pour la destruction, vous devez le faire en sens inverse, parce que si vous supprimez l'objet externe d'abord, vous auriez aucun moyen d'accéder aux pointeurs internes pour supprimer ceux-ci. Au lieu de cela, vous supprimez des objets internes à l'aide du destructor, le système d'exploitation gère la réelle libérant de la mémoire lorsque le flux de contrôle tombe du destructor.

Par ailleurs, le même genre de chose se produit avec subclassing-- si vous avez la classe A et classe B: Un public, lorsque vous faites une nouvelle B (), les exécute constructeur A, puis le constructeur de la B; sur la destruction, les exécute destructor du B en premier, suivi par des A. Je suis assez sûr que vous n'avez pas à vous inquiéter à ce sujet, though-- C ++ prend en charge pour vous. Donc, ne pas essayer de trouver un moyen d'appeler de suppression sur la superclasse.


0 commentaires

2
votes

Avant toute autre chose: j'espère vraiment que ce devoir vous assignent afin de comprendre une liste doublement liée. Sinon, il n'y a aucune raison d'utiliser cela au lieu de std :: Liste code>. Avec cela hors de la route:

Non, Supprimer ce code> dans un DTOR est toujours faux, car le DTOR est appelé lorsque Ce code> est dans l'état d'être supprimé. p>

aussi, tandis que p>

DoublyLinkedList::~DoublyLinkedList()
{
    delete first();
}


2 commentaires

Pas devoirs, mais c'est un exercice d'apprentissage. Je n'ai jamais réellement utilisé une liste. Je suis fan de la STL, alors ne vous inquiétez pas pour ça.


@Hooked: un soupir de soulagement à cette fin. : ^>



0
votes

Les deux ne doivent jamais être faits.

Ceci P>

DoublyLinkedList::~DoublyLinkedList
{
    Node *temp = first();
    while( temp != NULL)
    {
        Node* next = temp->next();
        delete temp;
        temp = next;
    }
}


0 commentaires