die heiligen 3
-
hallo, ich habe eine Klasse CMeinObect die unter anderem Zeiger für andere Objecte verwaltet. Also bin ich gezwungen einen Destructor zu schreiben der allen verwalteten Referenzen nachgeht und sie vernichtet...
1. Nun sollte man ja auch einen Copy Consturctor schreiben, aber brauch ich diesen wenn ich mein Object nur mit <vector> und <list> verwende
Also z.B. vector<CMeinObject*> ?2. Wenn kein Copy Constructor verwendet wird, werden ja nur die Zeiger selber kopiert. Wird nach der Verwendung des Copy Constructors auch immer der Destructor aufgerufen? (Das würde ja die kopierten Zeiger auf Garbage zeigen lassen...). Inbesondere zielt meine Frage auf Verwendung mit list und vector ab?
Danke
-
ich-und-du schrieb:
hallo, ich habe eine Klasse CMeinObect die unter anderem Zeiger für andere Objecte verwaltet. Also bin ich gezwungen einen Destructor zu schreiben der allen verwalteten Referenzen nachgeht und sie vernichtet...
Sobald du einen Destruktor benötigst, ist die Wahrscheinlichkeit recht hoch, das auch ein Kopierkonstruktor und Zuweisungsoperator benötigt wird (oder alternativ: sie verbieten).
ich-und-du schrieb:
1. Nun sollte man ja auch einen Copy Consturctor schreiben, aber brauch ich diesen wenn ich mein Object nur mit <vector> und <list> verwende
Also z.B. vector<CMeinObject*> ?Solange du mit normalen Zeigern hantierst, und diese Zeiger nicht nur informativen Charakter haben, musst du dich auch immer um Kopierkonstruktor & Zuweisungsoperator kümmern.
Die STL Container sind für Objekte, nicht Zeiger, ausgelegt (Du kannst sie zwar mit Zeigern verwenden, bist aber auch in jeden Fall für die Freigabe verantwortlich!).
ich-und-du schrieb:
2. Wenn kein Copy Constructor verwendet wird, werden ja nur die Zeiger selber kopiert.
Es wird für jedes Objekt der Klasse der Kopierkonstruktor aufgerufen, für Basisdatentypen ist dies eine 1:1 Kopie des Inhaltes im Falle eines Zeigers die Adresse.
ich-und-du schrieb:
Wird nach der Verwendung des Copy Constructors auch immer der Destructor aufgerufen? (Das würde ja die kopierten Zeiger auf Garbage zeigen lassen...). Inbesondere zielt meine Frage auf Verwendung mit list und vector ab?
list und vector machen hierbei KEINERLEI Unterschied, solange du normale Zeiger verwendest.
Nehmen wir mal einfach an du hast eine Klasse A:
{ A a; // Standardkonstruktor a A b(a); // Kopierkonstruktor b A c = a; // Kopierkonstruktor c b = c; // Zuweisungsoperator } // <-- Destruktor für c, b, aWenn a hierbei einen Zeiger enthält (oder einen Container mit Zeigern), wird nach der Kopie oder Zuweisung die gleiche Adresse in dem Zeiger / Container stehen... Logisch das, wenn du nur dem Destruktor überschreibst, und darin die Zeiger freigibst, du nach dem ersten Destruktoraufruf nur noch Müll vorliegen hast (und mit ziemlicher Sicherheit mit weiteren Destruktoraufrufen eine Access Violation auslöst...).
NACHTRAG: Was hast du eigentlich von vector, list etc. erwartet? Sie kümmern sich nur darum das Objekte verwaltet werden, das heist das sie z.B. mit Kopierkonstruktor und Destruktor arbeiten - Ein Destruktoraufruf eines Zeigers löst aber kein delete auf das Objekt aus, auf dem die Speicheradresse zeigt.
-
Ein Destruktoraufruf eines Zeigers löst aber kein delete auf das Objekt aus, auf dem die Speicheradresse zeigt.
danke. soetwas habe ich mir schon gedacht.
1. aber wenn ich jetzt im vector nur zeiger verwalte, habe ich gedacht vector wäre so klug das zu erkennen und eben nur den verwalten zeiger auf das MEinObject in seiner datenstruktur zu kopieren und MeinObject ganz in Ruhe lässt. Aber das ist ja nicht so, oder wie???
2. Bei der vernichtung des vectors gehe ich durch alle elemente durch und rufe delete auf (das löst ja auch den destructor des object aus?), dann mache ich ein vector.clear und dann ein delete vector. Richtig so?
Danke
-
ich-bin-du schrieb:
1. aber wenn ich jetzt im vector nur zeiger verwalte, habe ich gedacht vector wäre so klug das zu erkennen und eben nur den verwalten zeiger auf das MEinObject in seiner datenstruktur zu kopieren und MeinObject ganz in Ruhe lässt. Aber das ist ja nicht so, oder wie???
Wenn du statt Zeigern Objekte verwenden würdest, würde er diese auch tatsächlich kopieren.
Aber wie sollte ein vector wissen wie er mit Zeigern verfahren soll?
Ein Zeiger könnte stellvertretend für ein Objekt stehen, das er verwalten soll, oder auch einfach als eine Form der Referenz (z.B. wenn an einer Stelle die Objekte verwalten werden, an anderer Stelle aber nur auf diese verwiesen werden soll).Wenn du Container haben willst, die über Zeiger Objekte verwalten solltest du dir mal Boost ansehen, Speziell die Pointer Container Library.
ich-bin-du schrieb:
2. Bei der vernichtung des vectors gehe ich durch alle elemente durch und rufe delete auf (das löst ja auch den destructor des object aus?), dann mache ich ein vector.clear und dann ein delete vector. Richtig so?
1. Es ist richtig das du mit dem delete auf einen Zeiger den Destruktor aufrufst, und es ist richtig, das du es für jeden Zeiger machen musst.
2. vector.clear ist aber in Destruktor unnötig, da nach dem Destruktoraufruf der Container auch ungültig wird und seinen Speicher bereinigt. clear musst du selbst nur aufrufen, wenn der vector anschließend noch benutzt werden soll.
3. Ein delete auf den vector ist nonsense, oder verwaltest du ihn etwa auch als Zeiger?Grundsätzlich: Für jedes new genau ein delete, für jedes new[] genau ein delete[].
Diese extreme Verwendung von new/delete deutet für mich tendenziell auf jemanden hin, der vorher mit Sprachen wie Java hantiert hat. Je nach dem wie häufig die Objekte kopiert werden, oder wie "kostenintensiv" die Kopie ist, mag ein vector mit Zeigern sinnvoll sein - ebenso wie die richtige Wahl des Containers einiges ausmachen kann. Aber alles und jedes mit Zeigern zu lösen ist auch falsch.
-
1. Nein es fast deine Objekte nicht an, es kopiert nur die Zeiger
2. Wenn du das so machst sollte das ok sein, kann aber trotzdem zu problemen führen wenn du das z.B. nicht nach einer Exception machst und der vector da zerstört wird. Der Speicher würde dann nicht aufgeräumt werden.Hier zu empfehlen wäre z.B. boost.ptr_container welches einen ptr_vector bietet. Das sich um die verwaltung von den Zeigern dann kümmert.
Alterantiv kannst du einen smart pointer (z.B. boost::shared_ptr) verwendenBR
Vinzenz
-
1. Nein es fast deine Objekte nicht an, es kopiert nur die Zeiger
Danke, dann bin ich ja auf der sicheren Seite, werde aber aus Prinzip trotzdem eine Copy Construktor schreiben.
Diese extreme Verwendung von new/delete deutet für mich tendenziell auf jemanden hin, der vorher mit Sprachen wie Java hantiert hat. Je nach dem wie häufig die Objekte kopiert werden, oder wie "kostenintensiv" die Kopie ist, mag ein vector mit Zeigern sinnvoll sein - ebenso wie die richtige Wahl des Containers einiges ausmachen kann. Aber alles und jedes mit Zeigern zu lösen ist auch falsch.
da hast du recht, aber ich bin der Meinung, dass bei einem Sigle Thread Programm jedes Object nur einmal vorhanden sein sollte und auch nicht rumkopiert werden muss, und auch bei multithread Programmen kann man seine Objecte richtig schützen. In Java ist das alles geschenkt, aber hier in meiner neuen Sprache c++ muss man an alles selber denken.
Ich brauch eigentlich nur irgendeinen container den ich ohne viel einbinde aufwand und externe Bibliotheken benutzen kann..
FRAGE: vector scheint also nur gut zu sein wenn da nicht zuviel unvorhersehbare bewegung drin ist. Wenn ich nun Objecte direkt reingebe und nicht deren Zeiger.
Aber wie ist das mit Listen? Ich gebe etwas hinein, dann wird es einmal in die neue Struktur kopiert und dann innerhalb der Liste wieder mit Zeigern verwaltet? Also wären die kosten nur das einmalige übergeben?
-
ich-bin-du schrieb:
FRAGE: vector scheint also nur gut zu sein wenn da nicht zuviel unvorhersehbare bewegung drin ist. Wenn ich nun Objecte direkt reingebe und nicht deren Zeiger.
Aber wie ist das mit Listen? Ich gebe etwas hinein, dann wird es einmal in die neue Struktur kopiert und dann innerhalb der Liste wieder mit Zeigern verwaltet? Also wären die kosten nur das einmalige übergeben?Das tolle an C++ ist, du kannst jederzeit den Containertypen ändern. Mach es erstmal mit vector, denn meistens ist vector der sinnvollste Container. Erst wenn du viele Elemente in die Mitte einfügst oder aus der Mitte löscht, wird vector schwach.
nimm also vector und wenn du feststellst dass es performance probleme gibt, dann probier mal deque und list aus. denn bedenke, dass feature dass man mit O(1) in der mitte löschen und einfügen kann bei einer std::list ist ja nicht gratis. die kosten dafür sind nicht trivial.
wenn es um pure performance geht sind oft auch die intrusive container von boost interessant.