Lista wskaźnikowa i wyciek pamięci

0

Napisałem listę wskaźnikową i podczas tworzenia 1000 elementów, a następnie ich usuwania w drugiej pętli nie dość że pamięć zajmowana przez program nie maleje to na dodatek rośnie. W przypadku gdy tworzę i usuwam po pierwszym elemencie okazuje się że program zajmuje mniej pamięci niż przy jego odpaleniu. Prosiłbym o jakieś wskazówki :)
Oto klasa

plik .h:

#include <string>
using namespace std;
struct Punkt{

	float x;
	float y;
	float z;
	Punkt * nastepny;  // wskaznik na nastepny element listy
};

class Lista
{
	Punkt *pierwszy;  // wskaznik na pierwszy element listy

public:

	void dodaj(string wybor,float x,float y, float z);
	void wstaw(int nr,float x,float y, float z);
	void usun(int nr);
	int wyszukaj(float x, float y,float z);
	Lista(void);
	~Lista(void);
};

.cpp :

#include "Lista.h"
#include <iostream>
#include <string>


using namespace std;

Lista::Lista(void)
{pierwszy = 0;										// zerowanie wskaznika wskazujacego na poczatek listy ( bo jest pusta)
}



void Lista::dodaj(string wybor,float x,float y, float z){			// dodaje element na koniec listy, przyjmuje stringa (p lub k) ktory mowi o tym,
																	// gdzie ma byc dodany punkt (poczatek lub koniec) oraz wspolrzedne do struktury

	Punkt * nowy = new Punkt;						// tworzymy nowy element listy
		nowy->x = x;
		nowy->y = y;
		nowy->z = z;
		nowy->nastepny = NULL;                         // ustawiamy wskaznik nowego elementu na 0

	if (pierwszy == 0){								// przypadek gdy lista jest pusta
		cout << "dodaje pierwszy"<<endl;
		pierwszy = nowy;								// ustawiamy wskaznik listy na pierwszy jej element na nowo stworzony element
	}
	else if((wybor == "p")&&(pierwszy != 0)){					// przypadek gdy lista nie jesty pusta i dodajemy element na poczatek
		cout << "dodaje na poczatek"<<endl;
		nowy->nastepny = pierwszy;					// nowy element wskazuje na ten ktory byl wczeesniej pierwszy
		pierwszy = nowy;							// wskaznik wskazujacy na pierwszy element listy wskazuje na nowy element
	}
	else if((wybor == "k")&&(pierwszy != 0)	)			// przypadek gdy lista nie jesty pusta i dodajemy element na koniec
	{   cout << "dodaje na koniec"<<endl;
		Punkt *temp = pierwszy;						// tworzymy zmienna pomocnicza sluzaca do przemieszczania sie po tablicy

		while(temp->nastepny){						// petla sluzaca do przemieszczenia sie wskaznikiem temp do ostatniego elementu tablicy
			temp = temp->nastepny;
		}
		temp->nastepny = nowy;						// byly ostatni element wskazuje na nowy element
	}
}

void Lista::wstaw(int nr,float x,float y, float z){		// wstawia element w dowolne miejsce listy, przyjmuje numer miejsa w ktorym ma znajdowac sie ten element oraz wspolrzedne do struktury


	if (nr == 1){
		Punkt * nowy = new Punkt;						// tworzymy nowy element listy
		nowy->x = x;
		nowy->y = y;
		nowy->z = z;

		nowy->nastepny = pierwszy;					// nowy element wskazuje na ten ktory byl wczesniej pierwszy
		pierwszy = nowy;							// wskaznik wskazujacy na pierwszy element listy wskazuje na nowy element

	}

	if (nr> 1){

		Punkt * nowy = new Punkt;						// tworzymy nowy element listy
		nowy->x = x;
		nowy->y = y;
		nowy->z = z;


		Punkt* temp = pierwszy;					// pomocniczy wskaznik
		int j= 1;								// zmienna pomocnicza sluzaca do identyfikowania numeru obiektu na ktorym sie znajdujemy

		while(temp->nastepny){					// przechodzimy na nastepny element do momentu az bedziemy przed interesujacym nas miejscem
			if(j+1==nr)break;
			temp = temp->nastepny;
		}

		if(temp->nastepny == 0 && j != nr)			//wskazanie elementu przekraczajacego liste

		if (temp->nastepny == 0 && j == nr){		// przypadek gdy dodajemy element na koniec listy

			temp ->nastepny = nowy;
			nowy ->nastepny = 0;
		}

		if (temp->nastepny != 0 && j == nr){		// przypadek gdy istnieje element na miejscu na ktore chcemy dodac

			nowy->nastepny = temp ->nastepny;		// nowo powstaly element wskazuje teraz na ten ktory znajdowal sie na jego miejscu
			temp->nastepny = nowy;					// element na miejscu nizszym od interesujacego nas wskazuje na nowy element

		}
	}
}

void Lista::usun(int nr){		            // usuwa element z listy, przyjmuje nr elementu ktory ma usunac

	if (nr == 1){				            // usuwanie pierwszego elementu
		cout <<"usuwam pierwszy"<<endl;
		Punkt *temp = pierwszy;				// tworzymy wskaznik ktory wskazuje na poczatek listy
		pierwszy = temp->nastepny;			// wskaznik na pierwszy element listy wskazuje teraz na drugi element listy
		delete temp;						// usuwamy byly pierwszy element listy
	}

	if (nr >1){

		Punkt *temp = pierwszy;					// tworzymy wskaznik ktorym bedziemy sie poruszac po liscie i ustawiamy go na poczatek listy
		int j = 1;								// tworzymy zmienna pomocnicza ktora pomoze nam znalesc nasz element

		while (temp){					        // ustawianie wskaznika przed miejsce ktore nas interesuje
			if(j+1 == nr){
            break;
			}
			temp = temp->nastepny;
			j++;
		}

		if(temp->nastepny == 0 && nr!=j){}		                //wskazanie elementu przekraczajacego liste - nie rob nic

		else if(temp->nastepny->nastepny == 0){		            // jesli usuwamy ostatni element listy;
			cout << "usuwam ostatni element"<<endl;
			delete temp->nastepny;
			temp->nastepny = 0;
		}

		else if(temp->nastepny->nastepny != 0){		                // jesli usuwamy element ktowy nie jest ani pierwszy ani ostatni
            cout << "usuwam srodkowy element"<<endl;
			Punkt *temp2 = temp->nastepny;						// wskaznik przechowujacy adred interesujacego nas elementu
			temp->nastepny = temp->nastepny->nastepny;			//element przed usuwanym elementem wskazuje na element za nim
			delete temp2;								        // usuwamy nas interesujacy element
		}
	}
}

int Lista::wyszukaj(float x,float y,float z){		// wyszukuje element o konkretnych wspolrzednych
	return 0;
}

oraz main przy ktorym wystepuje problem :

#include "Lista.h"
#include "cstdlib"

int main(){

	Lista *oLista = new Lista;
	system("pause");
	for(int i = 1; i<=1000;++i)
	{
		oLista->dodaj("k",1,1,2);
	}

	system("pause");

    for(int i = 1000; i>=1;--i)
	{
		oLista->usun(i);
	}

    system("pause");
	return 0;
}
0

Po pierwsze nie zwalniasz pamięci przydzielonej na listę. Po drugie naucz się korzystać z debuggera aby rozstrzygać czy program poprawnie zwalnia pamięć czy nie.

0
kamienikupa napisał(a):

Po pierwsze nie zwalniasz pamięci przydzielonej na listę

Co masz przez to na myśli? Czyli co zwalniam tymi moimi deletami?

0

Swoimi deletami zwalniasz pamięć przydzieloną na punkty, tymczasem pamięć przydzielona na obiekt klasy Lista wciąż jest zajęta.

Podpowiedź:

Lista *oLista = new Lista;

brak delete...

0

To program na zaliczenie, czy robisz sobie listę, bo nie wiesz, że C++ ma standardowe kontenery?

Przepuść program pod valgrindem, zobacz wyniki.

Przy okazji: znajdź jakiś lepszy kurs, używanie nagiego new i delete w kodzie to teraz antyidiom (mówię o tym w main, w liście od biedy ujdzie, chociaż tam też można to lepiej zrobić). Używanie stringa przekazywanego przez kopię zamiast enuma to nie jest najlepszy pomysł. Indeksacja od 1 również.

0

Oczywiście, że jest to program na na zaliczenie jednego z laboratoriów :D. Usunąłem w funkcji main tę listę i z pamięcią dalej problemy. Poczytam o tym valgrind'zie bo juz nie mam żadnego pomysłu ;/

1

Pomijając bezsensowność wstawiania w środek listy (pewnie macie przekonać się o tym na własnej skórze) przerób na takie podejście:

struct Punkt
  {
    float x,y,z;
    Punkt();
    Punkt(float x,float y,float z);
  };
 
class Lista
  {
   struct Node
     {
       Punkt p;
       Node *next,*prev;
     };
   Node *head,*tail;
   public:
   void addHead(const Punkt &p);
   void addTail(const Punkt &p);
   void insert(unsigned nr,const Punkt &p);
   void usun(iunsigned nr);
   int wyszukaj(const Punkt &p);
   Lista &operator=(const Lista &L);
   Lista(const Lista &L);
   Lista(Lista &&L);
   Lista();
  ~Lista();
  };

Usuń wszystkie cin/cout z metod, mają być w main.

0

Przebudowałem całą klasę tak jak mi napisałeś,wiem że cin i cout ma nie być w metodach, ale sprawdzałem w jakie if'y mi program wchodzi a w jakie nie(teraz juz uzywam debuggera), pominąłem na razie niektóre konstruktory, bo nie o to mi teraz chodzi i wiem że nie użyłem konstruktora struktury (nie wiem jak go użyć jak go użyć, jeśli ta struktura jest w klasie (klasa obiekt = new klasa.struktura(parametry) ? czy w konstruktorze klasy wykorzystać konstruktor struktury) ale znów mam wyciek pamięci (sprawdzam menedżerem urządzeń, bo tak mam w instrukcji do laboratorium), prosiłbym o jakieś dalsze wskazówki. Z góry dziękuję :) .

plik klasy .h

 
struct Punkt
  {
    float x,y,z;
    Punkt(){}

    Punkt(float x,float y,float z){
        this->x = x;
        this->y = y;
        this->z = z;
    }
  };

struct Node
{
    Punkt point;
    Node *next,*prev;
};
class Lista
  {
   Node *head,*tail;
   public:
   void addHead(const Punkt &p);
   void addTail(const Punkt &p);
   void wstaw(unsigned nr,const Punkt &p);
   void usun(unsigned nr);
   int wyszukaj(const Punkt &p);
   //Lista &operator=(const Lista &L);
   Lista(const Lista &L);
   //Lista(Lista &&L);
   Lista();
  ~Lista();
  };

plik klasy .cpp

 
#include "Lista.h"
#include <iostream>


using namespace std;

Lista::Lista(){
    head = 0;
    tail = 0;
}

Lista::Lista(const Lista &L){                   // konstruktor kopiuj¹cy
    this->head = L.head;
    this->tail = L.tail;
}

Lista::~Lista(){

}

void Lista::addHead(const Punkt &p){
    Node *nowy = new Node;
    nowy->point.x = p.x;
    nowy->point.y = p.y;
    nowy->point.z = p.z;

    if(head == 0){
    //cout << "dodaje pierwszy"<<endl;
        head = nowy;
        tail = nowy;
        nowy->next = 0;
        nowy->prev = 0;
    }

    else{
   // cout << "dodaje na poczatek"<<endl;
        nowy->next = head;
        nowy->prev = 0;
        head->prev = nowy;
        head = nowy;
    }
}

void Lista::addTail(const Punkt &p){
    Node *nowy = new Node;
    nowy->point.x = p.x;
    nowy->point.y = p.y;
    nowy->point.z = p.z;
    if(head == 0){
    //cout << "dodaje na poczatek"<<endl;
        head = nowy;
        tail = nowy;
        nowy->next = 0;
        nowy->prev = 0;
    }

    else{
    cout << "dodaje ostatni"<<endl;
        nowy->next = 0;
        nowy->prev = tail;
        tail->next = nowy;
        tail = nowy;
    }
}

void Lista::wstaw(unsigned nr,const Punkt &p){
    Node *nowy = new Node;
    nowy->point.x = p.x;
    nowy->point.y = p.y;
    nowy->point.z = p.z;

    if(nr == 0){
        if(head == 0){
            head = nowy;
            tail = nowy;
            nowy->next = 0;
            nowy->prev = 0;
        }

        else{
            nowy->next = head;
            nowy->prev = 0;
            head->prev = nowy;
            head = nowy;
        }
    }


    else {
        Node *temp = head;
        unsigned j = 0;

        while (temp->next){
            if(j=nr)break;
            j++;
            temp = temp->next;
        }

        if(temp->next == 0 && nr!=j){}                   // w przypadku podaniu indeksu przekraczajacego zakres listy

        else{                              // w przypadku gdy interesujacy nas element jest ostatni

            nowy->next = temp;
            nowy->prev = temp->prev;
            temp->prev->next = nowy;
            temp->prev = nowy;
        }
    }
}

void Lista::usun(unsigned nr){

    Node *temp = head;

    if(nr == 0){

        head = head->next;
        delete temp;
        cout << "usuwam pierwszy"<<endl;
    }

    else {
        unsigned j = 0;
        while (temp->next){
            if(j==nr)break;
            j++;
            temp=temp->next;
        }

        if(temp->next==0 && j!=nr){cout<<"blad"<<endl;}

        if(temp->next != 0){
        //cout << "usuwam ze srodka"<<endl;
            Node *temp2 = temp;
            temp->prev->next = temp->next;
            temp->next->prev = temp->prev;
            delete temp2;
        }

        if(temp->next == 0){
        cout << "usuwam ostatni"<<endl;
            temp->prev->next = 0;
            tail = temp->prev;
            delete temp;
        }
    }
}

int Lista::wyszukaj(const Punkt &p){
        Node *temp = head;
        unsigned j = 0;
        while(temp->next){
            if(temp->point.x == p.x && temp->point.y == p.y && temp->point.z == p.z)break;
            temp=temp->next;
            j++;
        }

        if(!temp->next){}                   // w przypadku nie znalezienia punktu o podanych parametrach

        else{
            return j;
        }
    }


plik main :

 
#include <cstdlib>
#include "Lista.h"
#include <iostream>

using namespace std;

int main()
{   system("pause");
    Lista *oLista = new Lista;


    Punkt p(1,2,3);
    for(int i = 0 ; i<1000 ; i++){
        oLista->addTail(p);
    }

    system("pause");
    
    for(int i = 999 ; i>=0 ; --i){
        oLista->usun(i);
    }

    delete oLista;
    system("pause");


     return 0;
}

0

Po kiego utrudniasz sobie życie? Wystarczy:

void Lista::addHead(const Punkt &p)
  {
   Node *nowy=new Node;
   nowy->point=p;
   nowy->next=head;
   nowy->prev=0;
   if(tail) head->prev=nowy; tail=nowy;
   head=nowy;
  }

Zaś jeżeli raczysz dodać konstruktor do Node to:

struct Node
  {
   Punkt point;
   Node *next,*prev;
   Node(const Punkt &point,Node *next,Node *prev):point(point),next(next),prev(prev) {}
  };

void Lista::addHead(const Punkt &p)
  {
   head=(head?head->prev:tail)=new Node(p,head,0);
  }
0

No dobra, dzięki, ale przydała by się pomoc z tą pamięcią ;/

1 użytkowników online, w tym zalogowanych: 0, gości: 1