Anfängerfrage, warum wird deconstructor so oft aufgerufen
-
Hallo zusammen
Ich habe eine simple Klasse "Person", welche den Namen der Person speichert und beim Aufruf des Deconstructors jeweils eine Ausgabe "deconstructor of Personname called". Hier des Beispielcode in abgekürzter Form:
//Create Persons on Stack Person John{"John", 32}; Person Marc{"Marc", 58}; Person Rene{"Rene", 45}; //Create a Tresor-Obj on Stack Tresor StackTresor{}; // Call method of Tresor which stores Persons in a vector StackTresor.storePerson(John); StackTresor.storePersonBySingleRef(Marc); StackTresor.storePersonByReference(Rene);
und hier die Methodenimplementation
void Tresor::storePerson(Person person) { myPersons.push_back(person); } void Tresor::storePersonBySingleRef(Person &person) { myPersons.push_back(person); } void Tresor::storePersonByReference(Person &person) { myPersonsPtr.push_back(&person); }
Ich erhalte folgende Ausgabe in der Konsole
constructor of John called
constructor of Marc called
constructor of Rene called
virtual deconstructor of John called
virtual deconstructor of John called
virtual deconstructor of John called
virtual deconstructor of Marc called
virtual deconstructor of Rene called
virtual deconstructor of Marc called
virtual deconstructor of John calledFrage: Warum wird der Deconstructor of John 4mal aufgerufen? Ich hätte dreimal erwartet.
Weil:
//Create Person on Stack
Person John{} 1xStackTresor.storePerson(John) 2x
{
vector.push-back(John) 3x
}
-
Du machst versteckte Kopien beim Einfügen in den Vector. Naja, so versteckt sind sie auch nicht, aber in deiner Ausgabe sind sie halt nicht sichtbar
Implementiere auch noch einen Kopierkonstruktor mit einer Ausgabe, dann siehst du auch das Erstellen dieser Kopien. Wenn du gründlich sein möchtest, auch noch den Zuweisungsoperator (wobei der aber keine neuen Objekte erzeugt, und zumindest in deinem derzeitigen Programm auch nicht genutzt wird). Damit kannst du das Leben eines Objekts vollständig verfolgen.
-
...und auch ein
vector.push_back
kann je nachcapacity
undsize
dafür sorgen, dass die bislang existierenden Objekte in neuen Speicherbereich umkopiert werden müssen - nämlich wenn die neue Größe zu groß wird (es werden deine Objekte auch gemovet, wenn dein Move-Konstruktornoexcept
ist) Dadurch kannst du also auch einen Destruktorcall bekommen.
-
Danke euch beiden für die Antworten. Dann werde ich einmal versuchen den Kopierkonstruktor mit einer Ausgabe zu implementieren und führe den Test nochmals durch. Danke auch für die Info, dass die Vector-Klasse "selbständig" unter gewissen Bedingungen einen Move/Copy durchführt
-
Deconstructor
Es heisst zwar "Destruktor", aber "Dekonstruktor" trifft es eigentlich auch ziemlich gut. Schliesslich sollten kompexere Objekte nicht einfach gespengt, sondern fein säuberlich demontiert werden
-
-
Ich habe jetzt noch den Kopierkonstruktor mit einer Ausgabe der Klasse Person hinzugefügt. Hier der Output:
constructor of John called -> wegen Person John{}
Copy constructor of John called -> wegen StackTresor.storePerson(John)
Copy constructor of John called -> wegen vector.push-back(John)
virtual deconstructor of John called -> ?
Copy constructor of John called -> ?
virtual deconstructor of John called
virtual deconstructor of John called
virtual deconstructor of John calledAlles nach -> habe ich eingefügt. Ich verstehe nicht was bei ? passiert
-
Du hast deinen Beitrag zwar gelöscht, aber ich kann die Frage vielleicht trotzdem für andere Leser beantworten:
void Tresor::storePerson(Person person) { myPersons.push_back(person); }
Das
person
in dieser Funktion ist ebenfalls eine Kopie und dieses Objekt wird beim Verlassen der Funktion zerstört. Das soll dein Programm ja vermutlich auch zeigen, da das bei storePersonBySingleRef nicht passiert.
-
@SeppJ Danke dir, macht Sinn
-
Ich habe noch eine Anschlussfrage:
//Create Persons on the Heap auto Rambo = new Person("Rambo", 44); //auto McClain = new Person("McClain", 39); auto Connor = new Person("Connor", 23); //Create a Tresor-Obj on Stack Tresor StackTresor{}; StackTresor.storePerson(Rambo); //Person* StackTresor.storePersonByCopyByReference(Connor); //Connor*
und hier die Methodenimplementation:
void Tresor::storePerson(Person *person) { myPersonsPtr.push_back(person); } void Tresor::storePersonByCopyByReference(Person *person) { myPersonsPtr.push_back(&*person); }
Frage: Ist es richtig, dass beide Methoden genau das gleich machen. Nämlich sie speichern einen Pointer zu einem Person-Obj in einem Vector<Person*>.
-
&*
hebt sich gegenseitig auf, also istperson
dasselbe wie&*person
.(Da sind übrigens nirgends Kopien oder Referenzen in deinem storePersonByCopyByReference)
-
@SeppJ Super, danke dir :). Ja, meine Methodennamen sind komplett irreführend und falsch, da hast du recht.