Cum pot dezaloca corect memoria alocată cu o listă legată? (Programare, C++)

CavemanAGz a intrebat.

Scriu un program care folosește o listă legată, iar în codul meu creez un pointer de obiect folosind cuvântul cheie „new”. Din câte am înțeles, de fiecare dată când folosești cuvântul cheie „new”, trebuie să ai și un „delete”, și mă întreb dacă fac acest lucru corect.

#include"gameClass.h"
#include"card.h"
#include"list.h"
#include"node.h"

using namespace std;

List::List()
{
    head = NULL;
}

List::~List()
{
    delete head;
}

void List::add(Card* tmpCard)
{
    if (head == NULL)
{
    Node* tmpNode;
    tmpNode = new Node;
    tmpNode->setNext(NULL);
    tmpNode->setData(tmpCard);
    head = tmpNode;
    delete tmpNode;
}
else
{
    Node* tmpNode;
    tmpNode = new Node;
    tmpNode->setNext(head->getNext());
    tmpNode->setData(tmpCard);
    head = tmpNode;
    delete tmpNode;
}
}

 Card * List::remove()
{
    if (head != NULL)
{
    //Card* tmpCard;
    Node* tmpNode;

    tmpNode = new Node;
    tmpNode->setNext(head->getNext());
    tmpNode->setData(head->getData());
    head->setNext(tmpNode->getNext());
    delete tmpNode;
}
    return nullptr;
}

Comentarii

  • Instalați new head și ștergeți-l imediat?? Păcat… –  > Por MikeCAT.
2 răspunsuri
MikeCAT

O faceți complet greșit.

  • Introduceți un nou head și apoi delete noul head imediat. Este foarte rău.
  • remove() nu face practic nimic. Ea creează un nou Node, , îi stabilește niște parametri, apoi recuperează setul de date care ar trebui să fie același și delete noul Node.

Încercați acest lucru:

#include"gameClass.h"
#include"card.h"
#include"list.h"
#include"node.h"

using namespace std;

List::List()
{
    head = NULL;
}

List::~List()
{
    // delete all node currently have instead of only head
    while (head != NULL)
    {
        Node* tmpNode = head;
        delete head;
        head = tmpNode;
    }
}

void List::add(Card* tmpCard)
{
    if (head == NULL)
    {
        Node* tmpNode;
        tmpNode = new Node;
        tmpNode->setNext(NULL);
        tmpNode->setData(tmpCard);
        head = tmpNode;
        // do not delete the new node here!
    }
    else
    {
        Node* tmpNode;
        tmpNode = new Node;
        tmpNode->setNext(head); // the new head should be linked to current head, not the next node of current head
        tmpNode->setData(tmpCard);
        head = tmpNode;
        // do not delete the new node here!
    }
}

 Card * List::remove()
{
    if (head != NULL)
    {
        //Card* tmpCard;
        Node* tmpNode;

        // no creating new nodes to remove the first node
        tmpNode = head->getNext(); // remember where the next node is
        delete head; // remove the head
        head = tmpNode; // move the head
    }
    return nullptr;
}

UPDATE: Dacă doriți să returnați pointerul către cardul din nodul care urmează să fie eliminat, trebuie să utilizați remove() va fi ca aceasta:

 Card * List::remove()
{
    if (head != NULL)
    {
        Card* tmpCard;
        Node* tmpNode;

        tmpCard = head->getData(); // remember where the card pointed by head is
        tmpNode = head->getNext(); // remember where the next node is
        delete head; // remove the head
        head = tmpNode; // move the head
        return tmpCard; // return the card
    }
    return nullptr; // there are no cards in this list
}

Comentarii

  • Așadar, funcția de eliminare a fost configurată pentru a returna un pointer de carte, astfel încât să pot pune fiecare carte eliminată într-o altă listă legată unică (FILO) într-o ordine aleatorie. Am creat noul nod pentru a putea returna pointerul înainte de a fi eliminat, a fost acesta un mod greșit de a îndeplini această sarcină? –  > Por CavemanAGz.
  • Vrei să îl returnezi? Dar nu trebuie să îl returnezi. De asemenea, vrei să returnezi un pointer de card, așa că returnează un pointer de card, nu pointer la Node și nici crearea unui nou Node. –  > Por MikeCAT.
  • Mulțumesc pentru ajutor. am urmat primul exemplu și am ajuns la al doilea exemplu, în timp ce îmi dădeam seama cum să returnez ceea ce aveam nevoie.  > Por CavemanAGz.
bad_alloc

Pentru a evita problema, utilizați pur și simplu un std::shared_ptr<Node>. Pointerul va dezaloca ceea ce indică imediat ce iese din domeniul de aplicare (dacă niciun alt pointer partajat nu indică spre el).

Dacă vreți să exersați utilizarea lui new/delete, ați înțeles greșit ce face acesta: Creați un nou nod folosind new și apoi lucrați cu acel nod într-un anumit mod. Doar atunci când nodul nu mai este necesar, îl ștergeți. În momentul de față se întâmplă următoarele:

Node* tmpNode;
tmpNode = new Node;        // You get a new Node on heap.
tmpNode->setNext(NULL);    
tmpNode->setData(tmpCard);
head = tmpNode;            // Head now points to the new Node. All is well.
delete tmpNode;            // The Node both tmpNode and head point to is deleted!

Acum, atât head, cât și tmpNode conțin un pointer către memoria nealocată. Atunci când îl accesați, obțineți un comportament nedefinit. Ceea ce doriți, probabil, este să ștergeți toate nodurile în destructorul List și în nici un alt loc.

Comentarii

  • Vă mulțumesc pentru comentariile din codul meu, este foarte util! –  > Por CavemanAGz.

Tags: