Wyciek pamięci? - Visual C++ 2010

0

Witam forumowiczów,
piszę klasę macierzy i natrafiłem na ciekawy błąd przy przeciążaniu operatorów... Żeby lepiej to wytłumaczyć najpierw podam kłopotliwy kod:

class CMatrix
{
	unsigned nM, nN; //wiersze, kolumny
	double **Macierz;
 
public:
~CMatrix()
{
	for (unsigned i = 0; i < this->nM; i++) delete[] this->Macierz[i];
}

friend CMatrix operator+ (const CMatrix &a, const CMatrix &b)
{
	if ( (a.nM != b.nM) || (a.nN != b.nN) ) std::cout << "\nError";
	else
	{		
		CMatrix wynik(a.nM, a.nN);
	
		for (unsigned i = 0; i < a.nM; i++)
			for (unsigned j = 0; j < a.nN; j++) wynik.Macierz[i][j] = a.Macierz[i][j] + b.Macierz[i][j];
		return (wynik);
	}
}
};

Wykonanie tego kodu, powoduje błąd Block type is valid. Macierz wynik jest poprawnie sumowana. Czytając parę tematów doszedłem do wniosku, że problem leży w destruktorze, więc go wywaliłem :)

Program nie wyrzucił żadnego błędu. Sprawdzałem też w Menadżerze zadań czy pamięć jest prawidłowo zwalniana i... tak! I tu moje pytanie, czy nie powinno dojść do wycieku pamięci skoro nie usunąłem **Macierz, stworzonej przez operator new[], operatorem delete[]?

0

problem leży w destruktorze, więc go wywaliłem

WTF? Skoro przydzielasz pamięć dynamicznie to należy ją po zakończeniu pracy zwolnić.

czy pamięć jest prawidłowo zwalniana i... tak!

Bo OS jest mądrzejszy od ciebie i zwalnia całą pamięć zajmowaną przez twój program po jego zakończeniu. W wyciekach pamięci chodzi o to, że one są niebezpieczne podczas DZIAŁANIA programu, a nie po zakończeniu działania.

Popatrz na kod, w którym przydzielasz pamięć i zwalniając ją rób to w odwrotnej kolejności niż podczas przydzielania.

0

Nie zamieściłeś całego kodu, brak konstruktowa, którego używasz w operatorze +.
Podczas działania bez usuwania Macierz pamięć rośnie, a jak dodam delete [] Macierz, to nie rośnie.
I jeszcze jedno:

  for(i=0; i<10; i++){
    CMatrix a(3,3);
    CMatrix b(3,3);
    CMatrix c=a+b;
    printf("%d: a=%2d, b=%2d, c=%2d\n", i, a.id, b.id, c.id);
  }

Co znajdzie się w c? Zmienne z wynik i jej tablica? Owszem, ale ta tablica już dawno została zwolniona przy kończeniu operatora+, skopiowany został jej adres, a nie cała tablica. Dodałem zmienną pomocniczą id która jest wypisywana przy tworzeniu i usuwaniu, out:

C:83 //obiekt na stosie
C:86
C:77 //konstruktor klasy w operator+
!new: 77;  83, 86 //wynik z operatora +
delete 77 //koniec operatora+
0: a=83, b=86, c=77 //wynik z pętli
delete 77 //powtórne usunięcie macierzy o takim samym ID, a więc i o tym samym adresie tablicy, która już została zwolniona

I dalej otrzymuję stacka całego.
Używam GCC w wersji 4.5

0

W destruktorze powinno byc jeszcze zwolnienie pamieci tablicy tablic, bo inaczej jest wyciek pamieci

0

@Razi91
Czyli usuwam coś co już zostało usunięte? Ale, w którym momencie to się usuwa? Przy return w operator+? Zmienna wynik jest dobrze inicjowana, poprawnie się wszystko sumuje, nie może tylko jej zwrócić. Trochę pokombinowałem i tak napisana funkcja

 
friend CMatrix operator+ (const CMatrix &a, const CMatrix &b)
{
	CMatrix *wynik = NULL; //dodane
	if ( (a.nM != b.nM) || (a.nN != b.nN) ) std::cout << "\nError";
	else
	{		
		wynik = new CMatrix(a.nM, a.nN); //dodane
	
		for (unsigned i = 0; i < a.nM; i++)
			for (unsigned j = 0; j < a.nN; j++) wynik->Macierz[i][j] = a.Macierz[i][j] + b.Macierz[i][j];
		
		return (*wynik); //dodane
	}
	delete wynik; //dodane
}

pozytywnie obchodzi ten problem.

@stfu
Dzięki, poprawiłem destruktor :)

0

Mówiłem o destruktorze

 ~CMatrix()
{ 
    for (unsigned i = 0; i < nM; i++)
        delete [] Macierz[i]; 
    delete [] Macierz; // usuwa tablicę tablic
}

I uczyn operator czescia klasy, po co ma byc funkcja zaprzyjazniona?

1

Wyciek możesz mieć też w konstruktorze - najlepiej go pokaż.

Druga wersja operator+ jest na pewno gorsza.

0

Mimo zmiany destruktora, dalej wyskakuje ten sam błąd (tylko w operatorach). Konstruktor na życzenie:

CMatrix(unsigned m, unsigned n)
{
  Macierz = NULL;
  nM = m;
  nN = n;
  Macierz = new double*[nM];
  for (unsigned i = 0; i < nM; i++) Macierz[i] = new double[nN];
}

Konstruktor kopiujący czyli CMatrix(CMatrix)?

0

Ja bym chciał zobaczyć całą klasę jakby można było, bo przy tym konstruktorze i destruktorze nie wierzę, że jest wyciek.
Btw nie powinno byc unsigned int w pętli for?

0
MJay napisał(a)

Btw nie powinno byc unsigned int w pętli for?

unsigned samo w sobie to unsigned int, tak jak long to long int :)

Cała klasa? Wrzucam jako załącznik :)

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