2013-05-16 14 views
6

To tylko projekt testowy, który pozwala zrozumieć, jak działa dziedziczenie. Cat jest podklasą Mammal, która ponownie jest podklasą Animal.C++ Usuń tablicę wskaźników - podwójnie za darmo lub z korupcją

int main() 
{ 
    Cat* cat1 = new Cat("nosy grey", 1.0d, 3); 
    Cat* cat2 = new Cat("purply green", 2.0d, 4); 

    Cat* cats[] = {cat1, cat2}; 

    delete [] cats; 
} 

Tak naprawdę nie mogę tego zrobić, ponieważ wtedy dostaję to.

*** Error in `/home/max/git/info-2-ss/Blatt3/Aufgabe2/main.exe': double free or corruption (out): 0x00007fff55fd7b10 *** 
======= Backtrace: ========= 
/lib/x86_64-linux-gnu/libc.so.6(+0x80a46)[0x7f3a07452a46] 
/home/max/git/info-2-ss/Blatt3/Aufgabe2/main.exe[0x40178e] 
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5)[0x7f3a073f3ea5] 
/home/max/git/info-2-ss/Blatt3/Aufgabe2/main.exe[0x400d39] 

wyjście I kiedy moje konstruktory i destruktory są nazywane, więc gdy moje koty się stworzony mam coś takiego:

Called ctor of Animal with age: 3 
Called ctor of Mammal with hairLength: 1 
Called ctor of Cat with eyecolor: nosy grey 

Kiedy zmiana kodu nieco więc brzmi:

delete [] *cats; 

potem będzie już oczekiwać, że moi dtors nazywa się tak za każdym cat:

Called dtor of Cat 
Called dtor of Mammal 
Called dtor of Animal 

zamiast otrzymuję ten pojedynczy wiersz:

Called dtor of Cat 

Podsumowanie: Jak można skutecznie usunąć moje tablice, tak, że wszyscy moi dtors się nazywa?

+1

Najpierw powinieneś przeczytać o wskaźnikach i alokacji dynamicznej. 'cats []' jest przydzielany na stosie, nie można go "usunąć". Zamiast tego powinieneś iterować i użyć 'delete' do każdego elementu. –

+0

Nie używaj 'delete', chyba że użyłeś' new'. Masz przydzielenie sterty, pozwól mu się oczyścić. Rozważ uczenie się o 'std :: shared_ptr' i' std :: unique_ptr' - łatwiej będzie się nauczyć niż ręcznego zarządzania pamięcią. –

Odpowiedz

2

Należy użyć delete[] na tablicy tylko jeśli masz tej tablicy z new ...[]! W ten sposób:

Cat * cats = new Cat[2]; 
delete [] cats; 

Powyższe byłoby prawidłowe. Należy jednak zauważyć, że w tym przypadku nie można przekazywać argumentów do konstruktora.

Teraz twoja sprawa. Nie utworzyłeś tablicy z new, więc nie powinno usuwać samej tablicy (jest na stosie, a nie w sterty). Dlatego dochodzi do awarii delete[] cats. Następna, *cats traktuje tablicę jako wskaźnik i dereferencje, tzn. Zwraca element, na który wskazuje ten wskaźnik.Dla tablicy jest to początek tablicy: *cats jest tożsamy ​​z cats[0]. Dlatego tylko pierwsza pozycja zostanie usunięta przy drugiej próbie.

Wreszcie, odpowiedź: zamiast tego wszystkiego, usunąć każdy element indywidualnie. Dla Państwa prostym przypadku:

delete cat1; 
delete cat2; 

lub, bardziej ogólnie:

for(int i = 0; i < sizeof(cats)/sizeof(cats[0]); ++i) { 
    delete cats[i]; 
} 

Tutaj sizeof(cats)/sizeof(cats[0]) jest prosty trik, aby uzyskać liczbę elementów w tablicy przez podzielenie jej rozmiaru przez rozmiar elementu.

Dzięki temu można zwolnić pamięć, w której znajduje się każdy z obiektów Cat. Jeśli martwisz się pamięcią, w której znajduje się zestaw wskaźników - jest on na stosie, co oznacza, że ​​zostanie zwolniony automatycznie po powrocie z funkcji.

2
for(i = 0; i < len(cats)/sizeof(Cat); i++) { 
    delete cats[i]; 
} 

delete[] cats będzie pracował tylko gdybyś stworzył cats użyciu cats = new Cat[num_cats].

8

Ten

Cat* cats[] = {cat1, cat2}; 

Tworzy tablicę wskaźników do kotów z przechowalnią auto! Nie przydzieliłeś tablicy z new[], więc nie powinieneś jej wypuszczać z delete[].

+0

hm, myślę o tym pytaniu. Jak mogę sprawdzić, czy wskaźnik do tablicy jest wskaźnikiem do tablicy 'auto-storage'? – gaussblurinc

+0

@loldop, nie istnieje wiarygodny sposób, o ile wiem. Dlatego tak wiele wysiłku wkłada się w realizację różnych semantyki własności. Podstawowa zasada jest taka: tylko bezpłatne, co sam sobie wyznaczyłeś, a jeśli potrzebujesz czegoś, albo jawnie je udokumentuj, albo sklonuj. – StoryTeller

+0

, więc zarządzaj tylko tymi rzeczami, które posiadasz. dobra zasada – gaussblurinc

0

Nie trzeba usuwać samej tablicy, tylko jej elementów. Twoja macierz cats jest na stosie, ponieważ nie została utworzona przy użyciu new lub malloc.

Więc wszystko co musisz zrobić, to

delete cat1; 
delete cat2; 

lub równoważnie

delete cats[0]; 
delete cats[1];