"Torben W. Hansen" <mail@ins-intersoft.com> wrote in message
news:b96rr2$1jhm$1@news.cybercity.dk...
[8<8<8<]
> int main()
> {
> Basis* bptr = new Afledt;
> delete bptr;
> return 0;
> }
>
> ~Basis() findes _ikke_ i begge klasser. Selvom Basis:
Basis() er virtuel,
> så eksisterer der _ikke_ en Afledt:
Basis(), men derimod en
> Afledt:
Afledt(). Så skulle man jo tro at indholdet af vtabellen for
> "Afledt klassen" bliver: &Basis:
Basis() - og at denne så bliver
kaldt.
>
> Klø'en i nakken - hvor er det, at jeg fejler ?
Destructorer hører til gruppen "Special member function".
Destructoren ikke har et navn, men erklæres med en speciel syntax.
Hvis man tager vtbl synvinklen, vil det gælde at en virtuel destructor har
et fast index i den.
F.eks. kunne index 0 i vtbl til "Basis" pege på "Basis:
Basis", og så ville
index 0 i vtbl til "Afledt" på "Afledt:
Afledt".
Når man så skriver
delete bptr;
vil der blive lavet et opslag i vtbl og funktionen, der er angivet på index
0 vil blive kaldt.
Man kan også bare tage en mere abstrakt synvinkel og sige at
* når destructoren er virtual, vil destructoren der hører til den
dynamiske type blive kaldt
* når destructoren ikke er virtual, vil destructoren der hører til den
statiske type blive kaldt
uden at bekymre sig om hvorfor og hvordan.
I dit eksempel er den statiske type "Basis" og den dynamiske type "Afledt".
[8<8<8<]
> int main()
> {
> Bil skoda;
> skoda.Horn();
> return 0;
> }
>
> så kaldes destructoren;
Ja
> Men det gør den åbentbart ikke med brug af "new".
Nej
> Selvom man bør
> at rydde op med "delete" troede jeg faktisk at objekter automatisk blev
> "deleted" når man returnerede til operativsystemet - ups... det vil så
> sige, at jeg lavede memory leak !
Ja, du lavede en memory leak.
Hukommelse der allokeres med "malloc" bliver frigivet at programmets runtime
system når det terminerer.
Hukommelse der allokeres med "operator new" bliver ikke frigivet af
programmets runtime system når det terminerer.
Og hvad der er endnu vigtigere så er der ikke noget der sikrer at de
nødvendige destructorer bliver kørt - det almindelige er at de ikke bliver
kørt.
Derfor kan der forekomme resource leak, som operativsystemet ikke har
mulighed for at rydde op i.
På trods af operativsystemet kan klare nogle af problemerne, vil jeg
kraftigt anbefale at man pænt frigiver alt hvad man har allokeret.
> > Værktøjer som CodeGuard er utroligt nyttige.
> Uden at jeg ved det, så lyder det som en form intelligent regelchecker
Der findes 2 typer automatiske værktøjer til at finde fejl i C++ kode:
* statiske analysatorer
* dynamiske analysatorer
Selvom de har et overlap i typen af problemer de 2 typer kan finde,
supplerer de hinanden.
De statiske analysatorer kigger source-koden igennem og laver en analyse
hvor der kan afsløres en række problemer.
F.eks. findes der værktøjer der kan undersøge om man overtræder nogle af
Scott Meyers regler fra "Effective C++" og "More Effective C++".
Eksempler på statiske analysatorer er Lint, værktøjer fra Progamming
Research og egentlig også warnings fra compilererne.
F.eks. beskriver artiklen
http://www.stanford.edu/~engler/p401-xie.pdf
en statisk analysator, der fandt i en række problemer i Linux.
Microsoft siger at de har anvendt nogle statiske analysatorer i forbindelse
med at forbedre kvaliteten i Windows Server 2003.
De dynamiske analysatorer holder øje med et program mens det kører.
De kan f.eks. de holde styr på hvilke hukommelsesblokke der er allokeret, om
man frigiver dem og om man bruger hukommelse man ikke allokeret.
Eksempler på dynamiske analysatorer er BoundsChekcer, Purify og Valgrind.
CodeGuard er en dynamisk analysator.
Egentlig er CodeGuard blot en compiler-option til Borland C++ compileren i
henholdsvis Professional og Enterprise udgaven.
Den indsætter noget ekstra kode f.eks. hver gang man bruger en pointer.
F.eks. vil den i forbindelse med "strcpy" undersøge om den buffer der skal
kopieres over i er allokeret og er stor nok.
Venlig hilsen
Mogens Hansen