Überschreiben einer Variablen

  • Themenstarter Themenstarter C152778
  • Beginndatum Beginndatum
C

C152778

Hallo zusammen ! :)

Eine grundlegende Frage: Was passiert beim Überschreiben einer Variablen ?

Folgendes Beispiel brachte mich zum Nachdenken:
Code:
vector<int> v1;
vector<int> v2
v1.push_back(3);
v2.push_back(4);
v2.push_back(5);
v1 = v2;
Hier wird die Variable v1 durch den von v2 kopierten Wert überschrieben. Findet hierbei auch ein Destruktoraufruf von v1 statt?
Falls nein, was passiert dann mit dem in v1 intern dynamisch allozierten Speicher ? Dieser würde ja dann theoretisch nicht mehr freigegeben werden.

Oder habe ich hier einen Denkfehler?

Schöne Grüße, Cyraid
 
Hallo zusammen ! :)

Eine grundlegende Frage: Was passiert beim Überschreiben einer Variablen ?

Folgendes Beispiel brachte mich zum Nachdenken:
Code:
vector<int> v1;
vector<int> v2
v1.push_back(3);
v2.push_back(4);
v2.push_back(5);
v1 = v2;
Hier wird die Variable v1 durch den von v2 kopierten Wert überschrieben. Findet hierbei auch ein Destruktoraufruf von v1 statt?
Falls nein, was passiert dann mit dem in v1 intern dynamisch allozierten Speicher ? Dieser würde ja dann theoretisch nicht mehr freigegeben werden.

Oder habe ich hier einen Denkfehler?
Letzeres.

Grundsätzlich: was bei der Zuweisung von Objekten passiert hängt von der Definition des Zuweisungsoperators ab. Dieser ist einer der "großen Drei", die man (laut der "rule of the big three") für eine Klasse die andere Objekte bzw. Speicher verwaltet immer implementieren sollte, da die vom Compiler standardmäßig generierten Versionen nicht genügen. Die beiden anderen wären der Kopierkonstruktor und Destruktor.

Bei der Zuweisung eines std::vector an einen anderen laut deines Bsp. wird der Destruktor natürlich nicht aufgerufen (v1 wird doch nicht gelöscht, nur der Zustand von v1 ändert sich). Aber die Elemente von v2 werden nach v1 kopiert. Dabei wird alles getan was notwendig ist, d.h. der interne Speicher wird evtl. erweitert wenn die Kapazität nicht ausreicht usw. Danach gilt (falls keine Ausnahme aufgetreten ist) v1.size == v2.size und v1[i] == v2[i] für alle i, 0 <= i < v1.size, also kurzum v1 == v2.

Gruß
 
@deepthroat: Danke für die ausführliche Antwort ! Super, das hilft meinem Verständnis schon viel weiter ! :)

Wie verhalten sich die big three, wenn man sie nicht selbst definiert?
Wann sollte man sie selbst definieren? Was sind typische Kennzeichen bzw. kritische Eigenschaften einer Klasse die es notwendig machen, sie selbst zu definieren?

Viele Grüße, Cyraid
 
Wie verhalten sich die big three, wenn man sie nicht selbst definiert?
Der Standard-Kopierkonstruktor und der Standard-Zuweisungsoperator kopieren beide lediglich stumpf die Membervariablen. Der Standard-Destruktor macht überhaupt nichts.

Wann sollte man sie selbst definieren? Was sind typische Kennzeichen bzw. kritische Eigenschaften einer Klasse die es notwendig machen, sie selbst zu definieren?
Einfache Faustregel: definierst du einen der großen Drei, solltest du auch die zwei anderen definieren. Insbesondere also, wenn die Klasse eigenen (Heap-)Speicher verwaltet.

Grüße,
Matthias
 
@Matthias: Danke für deine Antwort.

Der Standard-Kopierkonstruktor und der Standard-Zuweisungsoperator kopieren beide lediglich stumpf die Membervariablen. Der Standard-Destruktor macht überhaupt nichts.

D.h. hier wird für jede Membervariable deren Kopierkonstruktor bzw. Zuweisungsoperator aufgerufen?
Dieser könnte dann je nachdem um was für einen Typ es sich bei der Variablen handelt widerum der Standard Kopierkonstruktor bzw Zuweisungsoperator oder ein selbstdefinierter sein. Sehe ich das richtig?

Einfache Faustregel: definierst du einen der großen Drei, solltest du auch die zwei anderen definieren. Insbesondere also, wenn die Klasse eigenen (Heap-)Speicher verwaltet.

Beispiel: Hält man in einer Klasse einen integer pointer int * a sollte man sich (sofern der pointer nicht woanders noch genutzt wird) einen Destruktor schreiben, der beim Löschen des Objekts delete(a) aufruft?

Viele Grüße, Cyraid
 
Beispiel: Hält man in einer Klasse einen integer pointer int * a sollte man sich (sofern der pointer nicht woanders noch genutzt wird) einen Destruktor schreiben, der beim Löschen des Objekts delete(a) aufruft?

Du musst im Destruktor einfach all den Speicher freigeben, der nach dem Ableben der Instanz der Klasse nicht mehr verfügbar sein soll oder nicht mehr verwendet wird.
 
D.h. hier wird für jede Membervariable deren Kopierkonstruktor bzw. Zuweisungsoperator aufgerufen?
Dieser könnte dann je nachdem um was für einen Typ es sich bei der Variablen handelt widerum der Standard Kopierkonstruktor bzw Zuweisungsoperator oder ein selbstdefinierter sein. Sehe ich das richtig?
Ja, das ist so richtig.

Beispiel: Hält man in einer Klasse einen integer pointer int * a sollte man sich (sofern der pointer nicht woanders noch genutzt wird) einen Destruktor schreiben, der beim Löschen des Objekts delete(a) aufruft?
Ja, denn sonst entsteht ein Speicherleck.

Grüße,
Matthias
 
@Cromon und Matthias: Vielen Dank euch für eure Antworten, jetzt ist es mir klar geworden :)

Schöne Grüße, Cyraid
 
Zurück