shared_ptr - Delete?
-
Skym0sh0 schrieb:
Doch, eine Fehlerquelle gibt es:
some_func(shared_ptr<Foo>(new Foo()), shared_ptr<Bar>(new Bar()), func());
also wird sowas hier vermutlich auch probleme machen oder?
m_Commands.insert(_Command("set_screen_width", shared_ptr<_IStrategy>(new _cmdScreenWith()), shared_ptr<_IStrategyVal>(new _valScreenWidth())));
TNA schrieb:
Am besten sowas gar nicht erst angewöhnen.
Ok, Ich habe vorher mit Raw Pointer gearbeitet. Mir wurde nur abgeraten das weiter zu machen.
So wie ich das mitbekommen habe war ein oder mehrere smart pointer nur in den neuen c++ standarts vorhanden.
Was gäbe es denn für alternativen?Ich vermeide Call by Value immer wenn irgendetwas übergeben wird das größer ist als 4 byte. Ich habe mir in vielen fällen das "const&" angewöhnt. Aber gerade bei Dingen wie Datenklassen die an jede klasse weiter gereicht werden, kam mir das shared_ptr Konzept sinvoll vor.
edit:
bzw wenn ich eine lösung für folgendes problem bekomme würde ich sehr viel new spaaren:Wie kann ich in folgendem Code, die erstellung von m_iKin ohne irgendein new schreiben? Bemerkung: Der Konstruktor von iKin bekommt mehrere Parameter.
class leg : public Observer { private: shared_ptr<iKin_math> m_iKin; }; leg :: leg() { m_iKin = shared_ptr<iKin_math>(new iKin_math(...Vars...)); }
-
cl90 schrieb:
Wie kann ich in folgendem Code, die erstellung von m_iKin ohne irgendein new schreiben?
class leg : public Observer { private: iKin_math m_iKin; }; leg :: leg() : m_iKin(...Vars...) { }
-
ah
da war ja sowas wie eine initialisierungsliste... jetzt wo der Wink mit dem Zaunpfahl kommt errinnere ich mich.danke dir!
-
Ich verstehe nicht, wieso Du immer mit Raw-Pointer argumentierst, wenn man Dir von shared_ptr abrät. Weißt Du nicht, dass es in C++ automatische Objekte gibt wie in krümelkackers Code vorgestellt? Das ist weder Raw- noch Smart-Pointer. Wenn das Beispiel nur irgendwie illustriert ist und gar nicht den eigentlichen Code widerspiegelt, okay. Aber in dem Beispiel sind weder Raw-Pointer noch Smart-Pointers empfehlenswert.
Ich habe mir in vielen fällen das "const&" angewöhnt. Aber gerade bei Dingen wie Datenklassen die an jede klasse weiter gereicht werden, kam mir das shared_ptr Konzept sinvoll vor.
"Ich fahre eigentlich gern mit dem Auto zur Arbeit, aber für die Uni erschien es mir besser die schwarze Hose zu tragen."
shared_ptr sind dazu gedacht Besitzverhältnisse zu klären, geteilte nämlich. Die werden nicht genutzt, um die Übergabe an Funktionen/Klassen anders zu handhaben. Einer Klasse, die einen Verweis (ohne Besitzmacht!) über ein Objekt benötigt, einen Raw-Pointer zu übergeben, ist in Ordnung. An dieser Stelle geht es aber auch nicht um Besitz, denn die Klasse, welche das Argument erhält, muss sich ja nicht um new/delete/Speicherverwaltung kümmern.
Der Unterschied mag fein erscheinen, es ist aber wichtig sich darüber Gedanken zu machen, ob geteilter Besitz wirklich notwendig ist (und das ist eben fast nie der Fall). Wenn viele unterschiedliche Klassen ein Objekt nutzen, heißt das nicht, dass die das auch besitzen müssen.
da war ja sowas wie eine initialisierungsliste...
Das ist aber nicht der Punkt. Automatisches Objekt auf dem Stack wird hier genutzt, während Dein Code ein Objekt auf dem Heap (über new) abgelegt hat. Die Initialisierungsliste kannst Du auch nutzen, um letzteres zu erzeugen.
Entweder lassen sich in Deinem Denken noch einige Dinge verbessern oder es liegt nur am Ausdruck Deiner Argumente. Jedenfalls gibt es da was zu tun.
-
Eisflamme schrieb:
Jedenfalls gibt es da was zu tun.
Das ist der Plan. Das programm läuft Absturzsicher und macht keine Probleme, nur ich will a) die Leaks loswerden denn das kann vermutlich zu einem Problem werden, und b) "unsauberen" code durch "besseren" ersetzen.
Den Ansatz das raw pointer schlecht sind hab ich mitlerweile verworfen.
Ich werd hier nochmal alles durchlesen und versuchen alle Tipps anzuwenden.
-
cl90 schrieb:
Ok, Ich habe vorher mit Raw Pointer gearbeitet. Mir wurde nur abgeraten das weiter zu machen.
Das Problem sind nicht die Raw-Pointer, das Problem sind Raw-Pointer in Verbindung mit
new
. Denn bei denen musst du manuelldelete
aufrufen. Raw-Pointer, die auf ein Objekt zeigen, welches an anderer Stelle verwaltet wird (z.B. durch Smart-Pointer, oder weil es auf dem Stack liegt) sind kein Problem.
-
Das Problem ist, das man hier Anfängern shared_ptr und Konsorten um die Ohren haut, bevor sie überhaupt verstanden haben, was das Problem ist.
-
Das Problem ist, das man hier Anfängern shared_ptr und Konsorten um die Ohren haut, bevor sie überhaupt verstanden haben, was das Problem ist.
Also müssen sie erst verstehen, dass das Problem ist, dass man hier Anfängern shared_ptr und Konsorten um die Ohren haut, bevor sie überhaupt verstanden haben, was das Problem ist.
-
Im Prinzip ist die Geschichte mit automatisch delete aufrufen relativ überflüssig, wenn keine Exceptions im Spiel sind. Denn dann ist es noch überschaubar, an welchen Stellen Speicher deletet werden muss. Das bedeutet nicht, dass das dann schön ist oder keinerlei Fehler(Memory Leaks) auftreten können, aber in der Theorie würde das reichen.
Sobald aber Exceptions dazukommen geht die Ressourcen-Verwaltung nur noch sinnvoll und übersichtlich mit RAII.
Daher, vllt anfangs mal 2-3 Übungen machen mit new+delete, danach alles in RAII-Klassen einkapseln!
-
Ja ich versteh ja auch euren Standpunkt. Nur leider ist es an meiner Uni so das die Profs sich nicht darum scheren woher du die Sprache kennst, du sollst nur Ihre Projekte machen können. Das Man dann nicht die Zeit hat sich ein gutes Buch zur Hand zu nehmen und bei 0 Anzufangen ist leider vorprogrammiert.
Ich bin auch direkt eingestiegen, und hab mich durch Trial and Error "Weiterentwickelt". Und solche Grundlagen fehlen dann leider manchmal.Die ganzen Pointer/shared_ptr sachen waren übrigents gar nicht das Problem...
Das Problem liegt in der Allokierung der DirectX Ressourcen. Texturen und Meshes... Ich muss mich jetzt erstmal einlesen wie die Strukturen aufgebaut sind damit ich weiß wie ich die wieder löschen kann.
-
DirectX verwendet COM Objekte.
Löschen tut man diese nicht, man gibt nur "seine" Referenz auf sie frei. Und wenn das die letzte Referenz war, dann löscht sich das Objekt von selbst.Zum Referenz-Zählen verwendet man ->AddRef() und ->Release(). Bzw. spezialisierte Smart-Pointer Klassen die einem das abnehmen.
-
Skym0sh0 schrieb:
Im Prinzip ist die Geschichte mit automatisch delete aufrufen relativ überflüssig, wenn keine Exceptions im Spiel sind. Denn dann ist es noch überschaubar, an welchen Stellen Speicher deletet werden muss. Das bedeutet nicht, dass das dann schön ist oder keinerlei Fehler(Memory Leaks) auftreten können, aber in der Theorie würde das reichen.
Sobald aber Exceptions dazukommen geht die Ressourcen-Verwaltung nur noch sinnvoll und übersichtlich mit RAII.
Daher, vllt anfangs mal 2-3 Übungen machen mit new+delete, danach alles in RAII-Klassen einkapseln!
Wenn Exceptions im Spiel sind, dann erleichtern RAII und Smartpointer das Leben ungemein. Wenn keine Exceptions verwendet werden, dann erleichtern sie nur ein wenig, aber sie tun es doch. Also warum sollte man auf RAII und Smartpointer verzichten? Wobei ich mich auch frage, warum man auf Exceptions verzichten sollte.
Wobei auch ohne Exceptions gibt es genügend Möglichkeiten, die Freigabe von Resourcen zu übersehen. Also nehme ich es zurück, dass RAII und Smartpointer ohne Exceptions das Leben nur ein wenig erleichtern. Sie tun es auch ohne Exceptions ungemein
.
-
tntnet schrieb:
Wobei auch ohne Exceptions gibt es genügend Möglichkeiten, die Freigabe von Resourcen zu übersehen.
Wer geschickt programmiert, für den ist das auch ohne RAII übersichtlich (ohne Exceptions).
10-Zeilen-Funktionen + Ressourcenmanagement von Verarbeitung trennen = übersichtlicher Code.
-
Nur ist das Problem, dass RAII schon vom Design her Fehler vermeidet. Programmierer sind Menschen, das heißt sie machen Fehler. Und das heißt, auch ihr Code tendiert zu Fehlerhaftigkeit. RAII macht es schwerer, Fehler zu machen. Es kann neue hervorrufen, aber eine noch größere Reihe von Fehlern wird damit behoben.
-
öhm...
Mag mir das jemand erklären:void main() { // Erzeugt leaks CData data = CData(); } void main() { // Erzeugt keine leaks CData data(); } void main() { // Erzeugt keine leaks CData* data = new CData(); delete data; } // jetzt ein Konstruktor einer Klasse: DirectX_Device :: DirectX_Device(CData* cdata) { // Erzeugt leaks. m_xfiles.push_back("plate.x"); m_xfiles.push_back("lowPolySphere.x"); } DirectX_Device :: DirectX_Device(CData* cdata) { // Erzeugt Keine leaks. //m_xfiles.push_back("plate.x"); //m_xfiles.push_back("lowPolySphere.x"); }
Das mit "data = CData()" ist mir neu..
Und muss man Vectoren deleten?
-
void main() { // Erzeugt leaks CData data = CData(); }
Das kann gar nichts, denn es ist kein gültiges C++.
Und selbst wenn du den Rückgabetyp zuint
änderst, ist diese Variante genauso sicher wie die zweite.Und muss man Vectoren deleten?
Nein. Deswegen sind sie u.a. so angenehm.
-
cl90 schrieb:
void main() { // Erzeugt leaks CData data = CData(); }
Das sollte keine Leaks erzeugen. Vermutlich gibt es einen Bug im Copy-Konstruktor von
CData
. Das würde auch erklären, warum der Fall mitnew
keine Leaks erzeugt, denn dort wird nur der normale Konstruktor aufgerufen.Nebenbei: im zweiten Fall wird kein
CData
-Objekt angelegt, sondern eine Funktion ohne Parameter mit RückgabewertCData
deklariert. Was du vermutlich willst, istCData data; // ohne ()
Vermutlich erzeugt das auch keine Leaks, aus dem gleichen Grund wie im
new
-Fall.
-
ipsec schrieb:
cl90 schrieb:
void main() { // Erzeugt leaks CData data = CData(); }
Das sollte keine Leaks erzeugen. Vermutlich gibt es einen Bug im Copy-Konstruktor von
CData
.Deshalb erzeugt auch das push_back() Leaks, hast die Klasse kein Move und gibt der Copykonstruktor vorher erzeugte Handles oder was auch immer nicht frei, gibts bei jeder Kopie Leaks.
-
also:
CData data;
Erzeugt auch leaks.
Aber ich habe nur einen Konstruktor deklariert. Ich hab mit dem Copy Konstruktor nichts gedreht.
CData sieht so aus:
class CData { public: CData(); // Sehr viele Funktionen nach Muster get/set D3DXVECTOR3* get_TargetPtr(int leg); // bsp. private: // Die Entsprechenden Variablen zu get/set int m_ReadDelay; //bsp. }; CData :: CData() : m_UDPSocket(&m_Acceleration, &m_RollPitchYaw), m_CIni() // Erzeugt auch ohne die beiden Klassen Leaks. // Ich geh also davon aus das die ok sind. { // initialisierungen. Alles ohne new }
-
void main() { // Erzeugt leaks CData data = CData(); }
Dann erzeugt dieser Code-Schnipsel dadurch Leaks, dass der Konstruktor von CData aufgerufen wird...