Wyciek pamięci? - Visual C++ 2010

Odpowiedz Nowy wątek
2011-08-27 12:16
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[]?

Pozostało 580 znaków

2011-08-27 12:29
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.


Pozdro & poćwicz!

Pozostało 580 znaków

2011-08-27 13:09
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

Pozostało 580 znaków

2011-08-27 15:26
0

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


Gdy się nie wie, co się robi, to dzieją się takie rzeczy, że się nie wie, co się dzieje ;-)

Pozostało 580 znaków

2011-08-27 15:34
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 :)

wywal ten delete wynik na końcu, bo poza psuciem nic nie robi (usuwasz NULL) - byku_guzio 2011-08-27 15:39
Nie rób tak!!! Będziesz miał na pewno wyciek pamięci. Zamień wynik z CMatrix* na CMatrix, jeżeli wystąpi błąd rzuć wyjątkiem (lub jak nie lubisz wyjątków zwróc macierz pustą). Do tego jak się wymiary nie zgadzają, teraz nic nie zwrócisz. - Zjarek 2011-08-27 15:59

Pozostało 580 znaków

2011-08-27 16:06
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?


Gdy się nie wie, co się robi, to dzieją się takie rzeczy, że się nie wie, co się dzieje ;-)

Pozostało 580 znaków

2011-08-28 13:46
1

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

Druga wersja operator+ jest na pewno gorsza.

Pozostało 580 znaków

2011-08-28 15:33

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)?

edytowany 3x, ostatnio: robin3d, 2011-08-28 15:37
No właśnie - a gdzie konstruktor kopiujący? - vpiotr 2011-08-28 15:36
Tak, bez niego będziesz miał wyciek. - vpiotr 2011-08-28 15:41
już poprawiam :) - robin3d 2011-08-28 15:42
brak konstruktora kopiującego powodował ten błąd, dzięki wielkie :) - robin3d 2011-08-28 15:59

Pozostało 580 znaków

2011-08-28 15:46
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?


Gdy się nie wie, co się robi, to dzieją się takie rzeczy, że się nie wie, co się dzieje ;-)

Pozostało 580 znaków

2011-08-28 15:50
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 :)

Nie używam takich skrótów bo zmniejszają przejrzystość kodu, dlatego się upewniam ;-) k jak dojadę do Krk to się przyjrzę. - MJay 2011-08-28 15:54
Dzięki :) - robin3d 2011-08-28 15:56
Przy operatorach też powinieneś mieć wyciek. - vpiotr 2011-08-28 17:40
dzięki, dobra strona :) - robin3d 2011-08-28 17:48

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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