Wer löscht?
-
Das kann man nicht pauschal sagen, beide Designs sind möglich. Du musst dir halt überlegen, ob C die Verantwortung für a und b übernimmt oder nicht.
-
Löschwilliger schrieb:
Meine Frage:
Wer soll nun den Speicher von a und b löschen? Der Dtor von C oder die Funktion, die a und b initiiert hat (und die Zeiger nur an C übergibt)?Ich persönlich bin kein Fan von Allozieren und Freigeben an unterschiedlichen Orten, da man dann gerade über solche Dinge stolpert. Entweder sollte C beides tun oder eben nicht.
Alternativ, wenn dies keine Option ist, und auch nicht genau zu klären ist wer was tut, ist shared_ptr/weak_ptr statt dem normalen Zeiger die richtige Option.
Enthalten entweder in boost oder in TR1.
#include <memory> // TR1 mit std::tr1 Namensraum oder // #include <boost/shared_ptr.hpp> bei Boost, mit dem boost Namesraum class A{}; class B{}; class C { public: C(std::tr1::shared_ptr<A> const & a, std::tr1::shared_ptr<B> const & b) : a(a), b(b) {} private: std::tr1::shared_ptr<A> a; std::tr1::shared_ptr<B> b; }; void main { std::tr1::shared_ptr<A> a(new A); std::tr1::shared_ptr<B> b(new B); C c(a, b); }cu André
Nachtrag: sobald dadurch ein gegenseitiges Aufrechterhalten passiert, muss man dies mittels weak_ptr auflösen... Aber ich schreibe jetzt keine Abhandlung über die Verwendung der Smartpointer, gibt garantiert dazu genug im Forum und in der boost-Hilfe.
-
Ich persönlich bin kein Fan von Allozieren und Freigeben an unterschiedlichen Orten
Ich wuerd noch weitergehen und sagen, das es definitiv kein guter Stil ist ... und ned nur ne persoenliche Abneigung

Also wenn technisch nix gegen spricht, sollten das new und delete immer an aequivalenten stellen zu finden sein, wie zb:
new: irgendwo in ner funktion/methode
delete: in der selben funktion/methode weiter hintennew: im Konstruktor/Initialisierungsliste einer Klasse
delete: im Destructor der klasse.besser:
new: in der initialisierungsliste als konstruktor parameter fuer nen smartpointer(member)
delete: automatisch.Ausnahmen:
gibts immer, klar. Wenn die lebenszeit einer Instanz definizieleren bedingungen unterliegt. Quelle /senken z.b. aber dann Smartpointer verwenden.
Objektfabriken ...Prinzipiell: new und deletes vermeiden, wenns geht. Oft kann man die dinger impliziet dynamisch anlegen lassen. zb in ne Liste werfen und nen zeiger auf das object in der liste weitergeben ... vorrausgesetzt die CCToren sind trivial (performance), und nen CCtor ueberhaupt logisch möglich ...
In deinem Fall wuerd ich mich fragen:
dein C wird eh dynamisch allokiert, warum dann die kosntruktion von a und b auch expliziet dynamisch ? warum ned in die konstruktion von C verlagern, und die Information zum erzeugen von a unf b an c (konstruktor) uebermitteln. dann koennen a und b normale member von c sein.
wenn nein, wer ist fuer a und b sonst zustaendig ?Ciao ...
-
ich denke, C sollte es keinesfalls freigeben.
Schließlich weißt du ja nicht, ob die im kontruktor übergebenen pointer im Heap oder Stack liegen.je nach Aufgabe deiner klasse würde sich folgendes anbieten:
class C { public: C() : m_a(new A) , m_b(new B) , m_freeMem(true) {}; C( A* a, B* b) : m_a(a) , m_b(b) , m_freeMem(false) {}; ~C() { if(m_freeMem){ delete m_a; delete m_b } } private: A* m_a; B* m_b; bool m_freeMem; }
-
vlad_tepesch schrieb:
ich denke, C sollte es keinesfalls freigeben.
Schließlich weißt du ja nicht, ob die im kontruktor übergebenen pointer im Heap oder Stack liegen.Genau das ist die Crux. Wenn `C` freigibt, müsste man diese Anforderung in der Dokumentation formuieren und es lässt sich sehr schwer die Korrektheit eines entsprechendne Programms überprüfen. Solche Besitzübergabe von Freispeicher ist immer eine äußerst heikle Angelegenheit und sollte gut durchdacht werden.
So allgemein, wie die Frage gestellt ist, sollte `C` den Speicher auf keinen Fall freigeben.
-
Benutze auto_ptr zur Parameterübergabe (wenn das Löschen der Objekt durch C überhaupt in Frage kommt). Dann beantwortet sich die Frage von selbst.
-
Löschwilliger schrieb:
Soll ich wie in Beispiel I oder II löschen?
Weder Beispiel I noch II sind Exception safe, d.h. das Programm muß umgeschrieben werden.
-
vlad_tepesch schrieb:
...
Grundsätzlich würde ich eine Schnittstelle möglichst frei von Mehrdeutigkeiten halten. Ja, solche Konstrukte wie dort geschrieben habe ich auch schon verwendet, aber nein, ich würde dies nicht wieder tun.
camper schrieb:
Benutze auto_ptr zur Parameterübergabe (wenn das Löschen der Objekt durch C überhaupt in Frage kommt). Dann beantwortet sich die Frage von selbst.
Zugegeben: Ich bin auch kein Fan vom als "deprecated" markierten auto_ptr, auch wenn er hier eine Option sein kann...
Ich weiß, der shared_ptr ist mit mehr Overhead versehen, aber seine Verwendung wurde im Laufe der Zeit nicht geändert, und er ist ab TR1 fester Bestandteil des Standards (und nicht "deprecated"). Zudem besagt er IMHO sehr schön was Sache ist.
cu André
-
RHBaum schrieb:
new: irgendwo in ner funktion/methode
delete: in der selben funktion/methode weiter hintenDas würde ich nicht machen. Das gibt mit Sicherheit keinen Exception-Sicheren Code. Deletes sind bei mir in der Regel immer in irgendeinem Destruktor. Oder genauer: in dem Destruktor der Klasse, welche die Objekte auch angelegt hat.
-
tntnet schrieb:
Das würde ich nicht machen. Das gibt mit Sicherheit keinen Exception-Sicheren Code. Deletes sind bei mir in der Regel immer in irgendeinem Destruktor. Oder genauer: in dem Destruktor der Klasse, welche die Objekte auch angelegt hat.
Es ging RHBaum wohl eher darum, wo dynamische Objekte zerstört werden sollen, wenn sie während einer Funktion erstellt werden. Und ein Destruktor kommt dann natürlich nicht in Frage.
Wenn man aber (rohe) Zeiger, die auf dynamischen Speicher verweisen, zurückgeben muss, kommt es nicht selten zu Memory Leaks, weil der Aufrufer nicht weiss, dass er das Objekt zu löschen hat (sieht man auch schön bei C-Funktionen).