Zeiger sicher verwenden?
-
Eigentlich sollte Bar aber einen Standardkonstruktor haben, so das du das ganze auch ohne Parameter initaliesieren kannst.
Wenn du das trozdem mit new und delete machen willst, ist es wohl das einfachste für dich die SmartPointer aus der Boost-Lib zu benutzen. Diese Pointer geben sich selbst frei, wenn sie nicht mehr gebraucht werden. Oder im d-tor einfach prüfen welche Zeiger deiner Klasse ungleich 0 sind und diese dann mit delete Freigeben. (Das setzt natürlich voraus, das du die Zeiger beim vorzeitigem löschen auch auf 0 setzt)
-
flammenvogel schrieb:
Eigentlich sollte Bar aber einen Standardkonstruktor haben, so das du das ganze auch ohne Parameter initaliesieren kannst.
Bar ist nicht von mir, die Klasse will ich adaptieren/wrappen. Die hat zwar einen Defalut C'tor, dann ist m_bar aber logischerweise leer, und ich muss alle Elemente einzeln über eine Iterator Schlaufe (wie bei STL Containern) einfüllen. Das bedeutet dann eine x-fache Speicherreallocation, da Bar intern mit Arrays arbeitet. Effizienter wäre, dem C'tor Anfangs- und Enditerator zu übergeben, denn dann nimmt Bar die Elemente direkt rüber in die eigenen Datenfelder, was scheints optimiert wurde.
// Also statt: Bar m_bar; for( it = it_begin; it != it_end; it++ ) { Bar::add_element( *it, m_bar ); } // einfach so: Bar m_bar( it_begin, it_end );
-
flammenvogel schrieb:
Oder im d-tor einfach prüfen welche Zeiger deiner Klasse ungleich 0 sind und diese dann mit delete Freigeben. (Das setzt natürlich voraus, das du die Zeiger beim vorzeitigem löschen auch auf 0 setzt)
Wesshalb nach einem "vorzeitigem" delete pointer dem pointer 0 zuweisen und im d-tor vor dem delete pointer auf pointer != 0 prüfen!?
Tipp: delete lässt 0-Zeiger in ruhe

Greetz, Swordfish
-
Tipp: delete lässt 0-Zeiger in ruhe

Warum macht DirectX dann immer diese SAFERELEASE Konstrukte?
Da wirds doch genau so gemacht?if( LPDIRECTXIRGENDWAS ) // LongPointer auf DXInterface, typedef für pointer { LPDIRECTXIRGENDWAS->release(); // Wohl ein Wrapper für delete oder nicht? LPDIRECTXIRGENDWAS = 0; }
-
Zeigerphobiker schrieb:
LPDIRECTXIRGENDWAS->release(); // Wohl ein Wrapper für delete oder nicht?oder.
das ist ein aufruf einer memberfunktion - und das ist nur legal, wenn LPDIRECTXIRGENDWAS auf ein lebendes objekt zeigt. dass release() ganz nebenbei evtl. noch für das löschen zuständig ist, spielt dabei keine rolle.
-
Ok, dann ist prüfen auf Null unnötig vor delete.
Wie ist es mit initialisieren? Wohin zeigt ein Zeiger, wenn er mit
Bar* m_bar;
angelegt wird? Auf 0? Oder muss ich erst
m_bar = 0;
im C'tor schreiben?
-
Du solltest deinen Zeiger mit 0 initialisieren, ansonsten steht irgendein Wert im Zeiger.
Am besten wirklich initialisieren nicht irgendwie zuweisen!
grüße
-
Was meinst Du mit "wirklich" initialisieren statt zuweisen?
Das Objekt kann ich erst in der init() erzeugen, s.o. warum.
-
Initialisiert wird per Initialisierungsliste. Wenn das Objekt dort nicht initialisiert wird, wird es mit einem Defaultwert initialisiert. Alle späteren Aktionen machst du also mit einem schon initialisierten Objekt.
Die Initialisierungsliste bietet u.A. den Vorteil das der C'tor Rumpf ggf nicht extra aufgerufen werden muss und dein Objekt nicht mit Defaultwerten vollgepumpt wird.
grüße
-
class Foo { public: Foo() : m_bar( 0 ), // Richtig so? m_x( 0 ), m_y( 0 ) { init_bar(); } ~Foo() { delete m_bar; // ohne check auf Null } private: void init_bar() { // get m_x and m_y from extern source.. m_bar = new Bar( m_x, m_y ); } Bar* m_bar; int m_x; int m_y; };Etwa so meinst Du?
-
class Foo { public: Foo() : m_bar( new Bar( 0, 0 ) ), // Richtig so? m_x( 0 ), m_y( 0 ) {} ~Foo() { delete m_bar; // ohne check auf Null } private: void init_bar() { // get m_x and m_y from extern source.. m_bar = new Bar( m_x, m_y ); } Bar* m_bar; int m_x; int m_y; };In dem Fall kannst du auf den Aufruf von init_bar verzichten.
-
class Foo { public: Foo() : m_bar( new Bar( 0, 0 ) ), // Erstelle hier ein Objekt m_x( 0 ), m_y( 0 ) {} ~Foo() { delete m_bar; } private: void init_bar() { // get m_x and m_y from extern source!! m_bar = new Bar( m_x, m_y ); // Und biege hier den Zeiger auf ein neues Objekt, was wird dann aus dem, das ich im Ctor erstellt habe? } Bar* m_bar; int m_x; int m_y; };new Bar( 0, 0 ) wollt ich eben eigentlich gern vermeiden..
-
Hi Zeigerphobiker,
ich habe mal eine ganz andere Frage: Wenn Foo eine Wrapperklasse von Bar sein (und Bar mit ihr sterben) soll, warum soll sie dann früher ins Leben gerufen werden als Bar ?
Oder hast Du eigentlich etwas Anderes vor, nämlich, dass FooBar ein Bar verwaltet (=komplett aggregiert und "Besitz übernimmt") ?
In dem Fall kann ich kein echtes Problem in Deinem ursprünglichen Vorgehen sehen. Du verwaltest im Pointer Bar* bar; im Grunde 2 Informationen:
1. Ob bar schon initialisiert wurde ("bar != 0") und
2. Wenn schon initialisiert: Wo die Daten liegen.
Dann ist ein "Foo(...) : bar(0), ... {...}" konsequent (also nicht ein leeres Objekt erzeugen).Allerdings stimmt schon: Du musst Dich um "Kopieren" (copyCtr, operator=()) kümmern, um Speicherlecks bzw. Doppeltlöschungen zu verhindern.
- Einfachstes: Kopieren verbieten (copyCtr und operator=() private machen) => STLContainer funktionieren nicht mehr ... aber das kann durchaus verschmerzbar sein.
- Alternativ: "Tiefe Kopie" => Kann unangenehm auf die Performance und den Speicherplatz drücken
- ... (gibt noch viele andere Konzepte bis hin zu globaler "bar-Objekt-Verwaltung")Gruß,
Simon2.
-
Also es ist so:
Foo::init_bar() erhält Informationen von Ausserhalb, füllt zwei Container (Member von Foo) mit diesen Informationen, und erzeugt dann Bar mit den Iteratoren der Container. Von daher war das Beispiel mit x und y etwas zu vereinfacht.
Bar ist also eine komplexe Datenstruktur aus einer fremden Lib.
Werd es dann so machen wie oben, ( "Foo(...) : bar(0), ... {...}" ) und CopyCtor und Op= verstecken, da ich eh nur ein Objekt Foo pro Anwendung erstelle.Danke euch allen und
schöne Grüsse