Lebenszyklus Initlist vs Konstukturbody
-
Mich beschäftigt gerade eine Frage, in der es um zwei Varianten der Objekt-Lebenszyklen geht.
Wenn ich hier von Variante 1 oder 2 schreibe, dann bedeutet dies, dass ich immer nur eine von beiden Zeilen meine und die andere dann automatisch nicht vorhanden ist.
Wenn ich in der Klasse B ein Objekt auf Variante 1 erzeugen, dann wird vor dem Konstruktor-Body von B der Konstruktor von A aufgerufen. Es wird also schon ein Objekt von A erzeugt, bevor der Scope des Konstruktors von B abgearbeitet wird. Dann wird zusätzlich im Konstruktor-Body nochmal ein Konstuktor von A aufgerufen und gleich wieder zerstört, wenn der Konstruktor fertig ist, ist das richtig so?
Das alte Objekt was vorher in _a war, existiert aber weiterhin und wird er beim Zerstören von B dann auch endgültig zerstört, oder?
class B { private: A _a; public: B() : _a( A() ) // Variante 2 { _a = A(); // Variante 1 } };Wähle ich stattdessen Variante 2, dann übernehme ich selbst das Erzeugen von _a und es gibt nur ein Objekt A und nicht zwei wie bei Variante 1, ist dem so?
-
_CppNeuland schrieb:
Wenn ich in der Klasse B ein Objekt auf Variante 1 erzeugen, dann wird vor dem Konstruktor-Body von B der Konstruktor von A aufgerufen. Es wird also schon ein Objekt von A erzeugt, bevor der Scope des Konstruktors von B abgearbeitet wird. Dann wird zusätzlich im Konstruktor-Body nochmal ein Konstuktor von A aufgerufen und gleich wieder zerstört, wenn der Konstruktor fertig ist, ist das richtig so?
Das letzte Objekt wird zerstört, wenn der Ausdruck fertig ist, in dem es auftaucht. So wie alle temporären Objekte.
Das alte Objekt was vorher in _a war, existiert aber weiterhin und wird er beim Zerstören von B dann auch endgültig zerstört, oder?
Vor was? Vor der Zuweisung? Die Zuweisung ändert doch keine Objektidentität. Das ist immer noch das gleiche _a. In _a ist kein Objekt, _a ist das Objekt. Es wurden ihm neue Werte zugewiesen.
Wähle ich stattdessen Variante 2, dann übernehme ich selbst das Erzeugen von _a und es gibt nur ein Objekt A und nicht zwei wie bei Variante 1, ist dem so?
Du erzeugst hier ebenfalls ein unnötiges temporäres Objekt, bloß ein bisschen früher und eventuell leichter wegoptimierbar.
P.S.: Das sind nur Fragen zur Erweiterung deines Wissens, oder? Du weißt, wie du Initialisierungslisten richtig benutzt, oder?
-
Naja, wenn immer wenn ich denke ich habe was verstanden, werde ich doch eines besseren belehrt und muss noch mal zu den Grundlagen zurück.
Bei Variente 1 ist mir halt aufgefallen dass ich zweimal einen Konstruktor von A aufrufe(einmal bei der Initialisierung des Members _a und einmal im Konstruktorrumpf) und folge dessen auch zweimal den Destruktor.
Bei der Variante 2 mit der Initialisiserungsliste habe ich nur einen Konstruktor- und Destruktor-Aufruf von A und daher dachte ich mir, dass diese Erzeugung von A resourcenschonender ist.
Mein Ziel ist es halt in einem Objekt von Klasse B ein Objekt von Klasse A zu erzeugen(abhängig von Parametern) und für die Lebensdauer von B dieses auch aufrecht zu erhalten. Wenn ich Variante 1 wählen dann wird mir das Objekt, was ich in dem Rumpf erzeuge, ja auch gleich wieder zerstört, sobald der Konstruktor von B fertig ist.
-
_CppNeuland schrieb:
Mein Ziel ist es halt in einem Objekt von Klasse B ein Objekt von Klasse A zu erzeugen(abhängig von Parametern) und für die Lebensdauer von B dieses auch aufrecht zu erhalten. Wenn ich Variante 1 wählen dann wird mir das Objekt, was ich in dem Rumpf erzeuge, ja auch gleich wieder zerstört, sobald der Konstruktor von B fertig ist.
Du meinst den Member _a?Entweder habe ich gerade keine Ahnung was du meinst oder du verstehst das Objektmodell von C++ nicht. Daher nochmal die Frage: Wie würdest du die Klasse B "normal" schreiben? Doch wohl nicht wirklich mit einer dieser beiden Varianten?
-
Ja das Objekt von A in der Klasse B soll der Member _a sein, um den dreht sich hier alles bei mir.
Die Frage wie ich die Klasse B schreiben will ich gerade hier erörtern. Das ist der Sinn und Zweck meiner Frage, da Klarheit rein zu bekommen.
Die dritte Möglichkeit die Klasse B zu schreiben wäre ein Zeiger auf A und dann per new ein Objekt von A zu erzeugen. Dann fällt mir noch eine Referenz auf A ein, die ich dann gleich in der Initlist mit einer Adresse belegen muss.
Mehr fällt mir nicht. Da ist mein erstes größeres C++-Programm, in Java und PHP stand ich vor solchen Problemen noch nie. Aber in C++ muss man sich schon viel mehr Gedanken machen wie was wo erzeugt, zerstört etc. wird.
-
dir ist schon bewusst:
class B { A _a; public: // standard-konstruktor -> standardkonstruktor von this->_a wird aufgerufen };und
class B { A _a; public: B() { } // konstruktor ohne explizite initialisierung von this->_a -> standardkonstruktor von this->_a wird aufgerufen };oder?
deine beiden beispiele sind... naja, unnötig. wieso möchtest du den kopierkonstruktor mit einem standard-konstruierten rhs ausführen? (variante 2) und wieso möchtest du zuerst standard-konstruieren und dann ein standard-konstruiertes objekt zuweisen? (variante 1)
-
Ich möchte einmal A _a mit Parametern erzeugen, also ohne dessen Standardkonstruktor.
-
huh? aber in deinem eröffnungspost hast du den kopierkonstruktor / zuweisungsoperator mit einem standard-konstruierten rhs aufgerufen. naja, wenn du die parameter des konstruktors eines members festlegen möchtest:
struct A { int data; A(int data) : data(data) { } }; class B { A _a; public: B(int data) : _a(data) { } };
-
Ah ok, das war mein Fehler, anstatt einfach den Parameter zu übergeben habe ich nochmals ein neues Objekt übergeben. Besten Dank, zusätzlich hatte ich noch die Zuweisung in Variante 1 nicht mit bedacht und ich dachte das erzeugt Objekt wäre verloren.
Ok, danke für die Hilfe hier ich muss mich noch mal ganz genau mit den Lebenszyklen beschäftigen. Wisst ihr da eine gute Zusammenfassung, in den Büchern ist dies meist ziemlich verstreut.