Archief - [PROG][C++] virtual destructor

Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.

forloRn_

Legacy Member
Gegroet,

Mijn handboek is wat onduidelijk. Stel dat je een klasse Person hebt, en een klasse Student (heel origineel, ik weet het) die ervan overerft, en een nieuwe stack-variabele int gpa toevoegt.

Code:
Student *s = new Student(...)
Person *p = s;
delete p;

De destructor van s wordt niet aangeroepen; wordt de variabele gpa vernietigd wanneer delete p wordt aangeroepen, of is er een memory leak?

Volgens mijn boek:
boek zei:
Any memory in the Student data fields that was allocated from the memory heap either directly (via calling new), or indirectly (e.g., if there is a string or vector as a data member) is never reclaimed and we have a subtle memory leak.

Nog volgens het boek is dit het default gedrag van een destructor:
boek zei:
The destructor is implemented by invoking destructors on each of the newly added data members, followed by invoking the destructor on the base class(es).

Moet je destructor virtual zijn als je subklasse enkel stack-variabelen toevoegt?

De eigenlijke reden waarom ik dit vraag, is omdat ze een paar bladzijden verder in het boek een vector <Shape *> maken, en de Shapes erin vernietigen met:
Code:
void cleanup(vector <Shape *> &a) {
  for (int i = 0; i < a.size(); i++)
    delete a[i];
}

In de vector komen *Circle's terecht, waarbij Circle overerft van Shape, en enkel een double radius toevoegt.

Volgens het boek:
boek zei:
cleanup simply steps through the array invoking delete. Observe that this would not work if the Shape class did not correctly declare a virtual destructor.

Vich

Legacy Member
Die vector <Shape *> moet je manueel doorlopen en alle Shape* eruit deleten manueel om het geheugen vrij te maken. Dit kan je bijvoorbeeld in de dtor doen. Maar als die dtor niet wordt aangeroepen(ivm niet virtual-zijn van de de basisklasse zijn dtor) dan wordt enkel de vector leeggemaakt en gewist, maar dus niet alle pointers naar die Shapes die erin zitten. Ofwel: hij wist enkel de lijst van pointers, niet de data die achter de pointer zit.
De vector zelf wordt dus wel leeggemaakt als die een member is van de klasse die wordt vernietigd.

forloRn_

Legacy Member
Jaja, dat weet ik. Het gaat erom dat met delete a, ~Shape() wordt aangeroepen, en niet ~Circle() omdat ~Shape() niet virtual is. Mijn vraag: is dat erg als Circle enkel een extra double bevat?

BuiZe

Legacy Member
Voor zover ik mij herinner onthoudt new bij elke allocatie hoe groot die was, zodat een delete op hetzelfde adres exact dat geheugen kan vrijgeven.

Nu, als je delete a; doet met Shape* a = new Circle(); wordt het object a zelf volledig vrijgegeven. Om extra allocaties die je in a hebt gemaakt te kunnen vrijgeven, wil je dat de destructor van Circle wordt opgeroepen voor die van Shape, en moet die van Shape virtueel zijn. Zonder extra allocaties in Circle zou de destructor van Circle toch leeg zijn, dus speelt het geen rol of die van Shape virtueel is (uiteraard niet proper als je wil dat mensen van je klasse kunnen afleiden).

Vich

Legacy Member
forloRn_ zei:
Jaja, dat weet ik. Het gaat erom dat met delete a, ~Shape() wordt aangeroepen, en niet ~Circle() omdat ~Shape() niet virtual is. Mijn vraag: is dat erg als Circle enkel een extra double bevat?


Die double maakt niks uit, die wordt automatisch gedelete. Het is enkel een probleem als je in Circle ook nog een "double* pointer = new double" had, omdat die dan niet automatisch wordt gewist, die heb je immers zelf manueel aangemaakt en moet je ook manueel wissen. Dat gebeurt dan normaal in de ctor of elders.

Van zodra je virtual members hebt in een basisklasse kan je best ook steeds de dtor virtual maken. Visual Studio geeft hier zelfs een warning over. Naar mijn mening kan je best voor elke klasse die wordt afgeleid door een andere de dtor virtual maken. Er zijn vast uitzonderingen waar dit niet hoort/mag maar ik ben er nog geen enkele tegengekomen.

killgore

Legacy Member
virtual destructor is enkel "slecht" als je in je afgeleide klasse die dynamische-geheugen objecten zelf gaat wijzigen, en dan nog is dit makkelijk op te lossen via gewoon consistent met NULL of 1 of andere boolean te werken.

Imho: elke destructor virtueel maken.

forloRn_

Legacy Member
Goed, dat dacht ik al. Dan is dat laatste stukje uit het boek gewoon onzin.

Bestaan er in feite profilers voor C++ die memory leaks detecteren? Ik ging tot nu toe altijd af op segmentation faults, maar ik heb gemerkt dat die niet altijd optreden als er een memory leak is.

Vich

Legacy Member
forloRn_ zei:
Goed, dat dacht ik al. Dan is dat laatste stukje uit het boek gewoon onzin.

Bestaan er in feite profilers voor C++ die memory leaks detecteren? Ik ging tot nu toe altijd af op segmentation faults, maar ik heb gemerkt dat die niet altijd optreden als er een memory leak is.

Buh Mingw(GNU GCC) zat er een bij die goed werkte (voor profilen én memory leaks). Dat programma noemt gprof.
Voor Visual Studio heb ik nog geen gratis profile gevonden. Het probleem is ook dat VS 2005 Express Edition geen plugins toelaat, waardoor je bijgevolg ook de meeste VS 2005 profilers niet kan draaien.
Ik zou ook wel willen weten of er een goeie profile bestaat. Zullen we een nieuw topic openen?

KeaTs

Legacy Member
Valgrind is een super tool, niet enkel voor memory leaks, maar zeker ook om buffer overruns te detecteren. t Zegt u waar de buffer overrun optreedt, ipv een hele tijd later ergens heel anders te crashen als gevolg van de buffer overrun. Enkel jammer dat er geen Windows-versie van bestaat :)
Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.
Terug
Bovenaan