Zeiger auf Vector von Zeigern
-
Hallo

Ich hab folgendes Problem:
Ich erzeuge einen Zeiger auf einen Vector von Zeigern
std::vector<Object*>* anObjectVector; anObjectVector = new std::vector<Object*>; for (it = anObjectVector->begin(); it != anObjectVector->end(); it++ ){ delete (*it); } anObjectVector->clear();Und obwohl ich mir außerdordentlich Mühe gebe, hat nach dem clear() der Vector size 367723 und ist voller CXX0030-Meldungen. Was mach ich falsch?
Viele Grüße,
C.
-
Zeig doch mal ein minimales, compilierbares, fehlerverursachendes Beispiel und nicht nur einen Codeschnipsel.
-
Deinen Fehler kann ich nicht reproduzieren.
Außerdem: So viele Sternchen und so viel new ist doof. Zeigt nur, dass Du C++ (noch) nicht effektiv einsetzen kannst (Stichwort RAII, damit wird der Kram auch Ausnahmesicher. Ausnahmesicher ist die verlinkte Version nämlich nicht).
-
Ehrlich gesagt, ich mach learning-by-doing mit dem super-effizienten Ansatz von meinem Betreuer, den ich nicht verstehe
Er sagt das ist ne vollkommene Lösung, da man den Überblick über alle Zeiger behält und sauber entfernen kann und Speicher gespart wird, und wenn man was mit dem Vektor macht verändert man nur den Zeiger. So oder so ähnlich - ich will dass er glücklich ist, aber verstehe die ganze Referenz auf Zeiger auf Referenz auf Zeiger-Sache nicht wirklich 
-
Cordula schrieb:
Ehrlich gesagt, ich mach learning-by-doing
Das kommt in C++ nicht gut. Klar musst du die Theorie anhand praktischer Beispiele vertiefen, aber dazu muss die Theorie erst einmal da sein. Es gibt einfach zu viele Regeln und Semantiken, ohne deren Kenntnis du verloren bist, und die du nicht durch Ausprobieren entdeckst.
Cordula schrieb:
Er sagt das ist ne vollkommene Lösung, da man den Überblick über alle Zeiger behält und sauber entfernen kann und Speicher gespart wird
Das ist viel eher vollkommener Schwachsinn.
- "Überblick behalten" -> Mit Zeigern entsteht leichter Chaos, also undefiniertes Verhalten (z.B. zwei Zeiger auf das gleiche Objekt, Dangling Pointers).
- "sauber entfernen" -> Ja, explizit entfernen. Und ab und zu vergessen oder doppelte Freigabe in Kauf nehmen. Benötigt mehr Code, der auch noch fehleranfällig ist.
- "Speicher sparen" -> Du benötigst mehr Speicher, weil jedes Element dynamisch allokiert wird, was jeweils einen kleinen Overhead mit sich bringt. Da ein
std::vectorohnehin schon dynamisch Speicher anfordert, hält sich der Gewinn dadurch in Grenzen.
-
Danke schön, ihr habt mir viel Zeit und Nerven gespart
Ich glaube sein Hauptpunkt war, dass man sonst an einer Stelle einen Zeiger auf etwas haben könnte, was schon an anderer Stelle gelöscht sein könnte.Also dazu meine Frage -
Ich mache folgendes - ich bekomme eine Anzahl von Zeigern auf Objekte, die ich dann entsprechend verschiedener Kriterien in mehreren unterschiedlichen Vektoren packe, z. B. das Objekt A ist -klein- und -rot-, also geht in den Vektoren vector<Objekt*> VectorKlein und vector<Objekt*> VectorRot. Nun, wenn ich den Destruktor starte, lösche ich brav nicht nur den Vektor mit clear, sondern auch alle Zeiger in dem Vektor:for (C = this->VektorKlein.begin(); C != this->VektorKlein.end(); C++){ if(*C != NULL){ delete (*C); } } this->VektorKlein.clear(); for (C = this->VektorRot.begin(); C != this->VektorRot.end(); C++){ if(*C != NULL){ delete (*C); } } this->VektorRot.clear();Nun, da ich in dem ersten Teil schon das ObjektA (oder den Zeiger auf ObjektA) gelöscht habe, beim Löschen von VektorRot kommt es dazu, dass drin ein Zeiger ist, aber das Objekt auf dem es zeigt schon gelöscht worden ist. Also hab ich es mir überlegt, es würde reichen, wenn nur die Farbenvektoren vollständig bereinigt werden, und die anderen (Größe und Form, z. B.) nur mit .clear(). Stimmt das oder laufe ich andere Gefahr an der Stelle ein?
VG,
C.Sorry für das doofe Farben-Größen-Beispiel, ich weiß nicht in wie weit ich Infos darüber, was ich tatsächlich mache, geben darf.
-
Für deinen Fall kommen eigentlich zwei Lösungen in Betracht:
-
du benutzt shared_ptr statt Rohzeiger, denn die unterstützen Reference Counting und erkennen, wann sie ihren Inhalt löschen müssen. Wenn deine Aufgabe allerdings ein Hausarbeit oder Ähnliches ist, die die Verwendung von Rohzeigern verlangt helfen dir auch die shard_ptr nichts. Du könntest vielleicht ein eigenes Reference Counting implementieren, aber das sprengt vermutlich den Rahmen der Aufgabe.
-
Im Moment sind deine beiden Vektoren (VektorRot, VektorKlein) besitzende Container, d.h. sie sind für das Löschen der in ihnen abgelegten Elemente verantwortlich. Wenn aber ein Objekt (als Zeiger) in mehreren Vektoren liegt darf nur einer dieser Vektoren den Besitz über das Element haben. Als mögliche Lösung könnte es einen besitzenden Master geben, der im Destruktor alle Elemente zerstört, und die anderen Vektoren enthalten zwar auch verschiedene Elemente, löschen sie aber nicht.
-
-
Nee, es ist meine Diplomarbeit, insoweit hab ich keine so strengen Vorgaben was ich verwende. Die Schnittstellen nach draußen (also die Zeiger auf Objekte) sollt ich allerdings nicht ändern, da ich sie nicht selbst geschrieben habe -> unberechenbare Folgen

Aber die zweite Lösung ist sehr interessant. Könntest du mir noch ein paar Stichwörter dazu geben dass ich mich weiter schlau machen kann?
Vielen lieben Dank schonmal

-
Ich glaube nicht, dass es dazu noch viel zu sagen gibt. Vielleicht kannst ja beide Lösungen kombinieren UND das Interface bedienen.
#include <boost/smart_ptr.hpp> class MyClass { // Typdefinitionen und Member für Fall 1 typedef boost::shared_ptr<Object> ObjectPtr_t; typedef std::vector<ObjectPtr_t> ObjectVector_t ; ObjectVector_t Master_; std::vector<Object*> VektorRot_; std::vector<Object*> VektorKlein_; public: MyClass(); // Fall 1 : Objekte werden selbst erzeugt, z.B. aus // einer anderen Datenstruktur oder durch Einlesen einer Datei, etc void add( const SomeDataType& Data ) { // Objekt für Master erzeugen ObjectPtr_t Obj = ObjectPtr_t( new Object() ); Master_.push_back( Obj ); // ggf. auf weitere Container verteilen if( ist_rot( Obj.get() ) { // Rohzeiger ablegen VectorRot_.push_back( Obj.get() ); } if( ist_klein( Obj.get() ) { // Rohzeiger ablegen VectorKlein_.push_back( Obj.get() ); } } // Fall 2 // Objekt wird von aussen bereitgestellt, da aber der Besitz übernommen // wird kann es in einen shared_ptr verpackt werden. void add( Object* Obj ) { Master_.push_back( ObjectPtr_t( Obj ) ); // ggf. auf weitere Container verteilen if( ist_rot( Obj ) ) { // Rohzeiger ablegen VectorRot_.push_back( Obj ); } if( ist_klein( Obj ) ) { // Rohzeiger ablegen VectorKlein_.push_back( Obj ); } } }Schön ist das aber nicht wirklich...
Für eine vernünftige Antwort fehlen noch ein paar Informationen:
- wie sieht der Zugriff auf den Inhalt der Vektoren VectorRot und VectorKlein aus?
- mit wievielen Objekte hantierst du? Kann man möglicherweise auf die Vektoren für einzelne Kategorien verzichten und den Zugriff über einen Filter Iterator (Beispiel: boost filtering iterator) oder temporäre Vektoren lösen?Edit:
Copy/Paste Bugs fixed
-
Cordula schrieb:
Aber die zweite Lösung ist sehr interessant. Könntest du mir noch ein paar Stichwörter dazu geben dass ich mich weiter schlau machen kann?
Damit ist einfach gemeint, dass du delete nicht für die Elemente VektorKlein und VektorRot aufrufst sondern nur für die Elemente eines neuen Vektors den du z.B. VektorAlle nennst. In den packst du einfach alle Objekte rein und nur er kümmert sich um das freigeben (sollte natürlich auch als letztes zerstört werden).