Här i programmet bilpekarna-2.cpp har jag lagt till destruktorer i klasserna Person och Motor (inte bara i Bil), och lagt till utskrifter i alla destruktorerna, så man ser vad som händer:#include <iostream> #include <string> using namespace std; // -------------- Klassen "Person" --------------- class Person { private: string namn; int alder; public: Person(string namn, int alder); }; Person::Person(string namn, int alder) { this->namn = namn; this->alder = alder; } // ---------------- Klassen "Bil" ---------------- class Motor { private: double effekt; public: Motor(double effekt); }; Motor::Motor(double effekt) { this->effekt = effekt; } // --------------- Klassen "Motor" --------------- class Bil { private: string bilnr; Person* owner; Motor* motor; public: Bil(string bilnr, Person* owner, Motor* motor); ~Bil(); }; Bil::Bil(string bilnr, Person* owner, Motor* motor) { this->bilnr = bilnr; this->motor = motor; this->owner = owner; } Bil::~Bil() { delete motor; } // -------------- Funktionen "main" -------------- int main() { Person goran("Göran", 58); Person* gudrunp = new Person("Gudrun", 57); Motor m1(110.0); Motor* m2p = new Motor(120.0); Bil bil1("RFN 540", gudrunp, m2p); Bil* bil2p = new Bil("BOS 118", &goran, &m1); delete bil2p; delete m2p; delete gudrunp; }
Här är bilden från föreläsningen på hur datastrukturerna ser ut, precis före första delete-anropet:#include <iostream> #include <string> using namespace std; // -------------- Klassen "Person" --------------- class Person { private: string namn; int alder; public: Person(string namn, int alder); ~Person(); }; Person::Person(string namn, int alder) { this->namn = namn; this->alder = alder; } Person::~Person() { cout << "Person-destruktorn körs. Personen " << namn << " tas bort.\n"; } // ---------------- Klassen "Bil" ---------------- class Motor { private: double effekt; public: Motor(double effekt); ~Motor(); }; Motor::Motor(double effekt) { this->effekt = effekt; } Motor::~Motor() { cout << "Motor-destruktorn körs. Motorn på " << effekt << " hk tas bort.\n"; } // --------------- Klassen "Motor" --------------- class Bil { private: string bilnr; Person* owner; Motor* motor; public: Bil(string bilnr, Person* owner, Motor* motor); ~Bil(); }; Bil::Bil(string bilnr, Person* owner, Motor* motor) { this->bilnr = bilnr; this->motor = motor; this->owner = owner; } Bil::~Bil() { cout << "Bil-destruktorn körs. Bilen " << bilnr << " tas bort.\n"; delete motor; cout << "Bil-destruktorn klar. Bilen " << bilnr << " har tagits bort.\n"; } // -------------- Funktionen "main" -------------- int main() { Person goran("Göran", 58); Person* gudrunp = new Person("Gudrun", 57); Motor m1(110.0); Motor* m2p = new Motor(120.0); Bil bil1("RFN 540", gudrunp, m2p); Bil* bil2p = new Bil("BOS 118", &goran, &m1); cout << "Ska börja städa upp i main.\n"; delete bil2p; delete m2p; delete gudrunp; cout << "Klar med main.\n"; }
Bill Gates har varit snäll, så Visual Studio kollar faktiskt vad man gör, så programmet gör inte bara fel i tysthet, utan avslutas med ett felmeddelande:
Även GCC under Linux ger ett felmeddelande:
Felen i programmet är flera:Ska börja städa upp i main. Bil-destruktorn körs. Bilen BOS 118 tas bort. Motor-destruktorn körs. Motorn på 110 hk tas bort. *** glibc detected *** double free or corruption (out): 0xbfe2c5b0 *** Abort (core dumped)
Några lärdomar som man bör ha med sig från den här övningen:
Utskrifter från bilpekarna-3:// -------------- Funktionen "main" -------------- int main() { Person goran("Göran", 58); Person* gudrunp = new Person("Gudrun", 57); Motor* m1p = new Motor(110.0); Motor* m2p = new Motor(120.0); Bil bil1("RFN 540", gudrunp, m2p); Bil* bil2p = new Bil("BOS 118", &goran, m1p); cout << "Ska börja städa upp i main.\n"; delete bil2p; // delete m1p; -- Nej! "Ägandet" har överförs till bilen. // delete m2p; -- Nej! "Ägandet" har överförs till bilen. delete gudrunp; cout << "Klar med main.\n"; }
(Notera att de lokala variablerna i main, i det här fallet goran och bil1, städas bort efter att sista satsen i main har körts.)Ska börja städa upp i main. Bil-destruktorn körs. Bilen BOS 118 tas bort. Motor-destruktorn körs. Motorn på 110 hk tas bort. Bil-destruktorn klar. Bilen BOS 118 har tagits bort. Person-destruktorn körs. Personen Gudrun tas bort. Klar med main. Bil-destruktorn körs. Bilen RFN 540 tas bort. Motor-destruktorn körs. Motorn på 120 hk tas bort. Bil-destruktorn klar. Bilen RFN 540 har tagits bort. Person-destruktorn körs. Personen Göran tas bort.
Kanske blir det lättast att inte alls blanda vanliga och new-allokerade variabler. Ur programmet bilpekarna-4.cpp:
Utskrifter från bilpekarna-4:// -------------- Funktionen "main" -------------- int main() { Person* goranp = new Person("Göran", 58); Person* gudrunp = new Person("Gudrun", 57); Motor* m1p = new Motor(110.0); Motor* m2p = new Motor(120.0); Bil* bil1p = new Bil("RFN 540", gudrunp, m2p); Bil* bil2p = new Bil("BOS 118", goranp, m1p); cout << "Ska börja städa upp i main.\n"; delete bil1p; delete bil2p; // delete m1p; -- Nej! "Ägandet" har överförs till bilen. // delete m2p; -- Nej! "Ägandet" har överförs till bilen. delete gudrunp; delete goranp; cout << "Klar med main.\n"; }
Ska börja städa upp i main. Bil-destruktorn körs. Bilen RFN 540 tas bort. Motor-destruktorn körs. Motorn på 120 hk tas bort. Bil-destruktorn klar. Bilen RFN 540 har tagits bort. Bil-destruktorn körs. Bilen BOS 118 tas bort. Motor-destruktorn körs. Motorn på 110 hk tas bort. Bil-destruktorn klar. Bilen BOS 118 har tagits bort. Person-destruktorn körs. Personen Gudrun tas bort. Person-destruktorn körs. Personen Göran tas bort. Klar med main.