Objekt als return, Destruktor löscht Memory.
-
Hallo,
Ich habe folgenden Aufbau einer Klasse:
MyClass { Public: double* Data; unsigned ItemCount; MyClass(); MyClass(unsigned Size); ~MyClass(); MyClass Test(); } MyClass::MyClass() { Data = new double[0]; ItemCount = 0; } MyClass::MyClass(unsigned Size) { Data = new double[Size]; ItemCount = Size; } MyClass::~MyClass() { delete[] Data; } MyClass MyClass::Test() { MyClass Temp(ItemCount); for(unsigned m = 0; m < ItemCount; m++) { Temp.Data[m] = Data[m]*m; } return Temp; }Der operator= kopiert sich dann die Daten (hier nicht gezeigt). Beim Aufruf von Test() wird eine neues Objekt Temp der Klasse MyClass erzeugt und richtig mit den Daten gefüllt. Beim Zurückgeben des Objektes wird jetzt jedoch erst der Destruktor aufgerufen und damit die Daten gelöscht.
Wie löse ich dieses Problem möglichst elegant?
Danke und GrüsseWilder
-
Da du ja den operator= und den dtor hast, musst du dich auch an die "Big Three" halten und den copyctor noch implementieren und in dem machst du einfach das was du in deiner Testmethode angestellt hast.
Und außerdem solltest du kein Temporäres Objekt zurückgeben sondern eine Referenz.
-
Wilder schrieb:
...Der operator= kopiert sich dann die Daten (hier nicht gezeigt)...
Wie wäre es wenn du genau den Zuweisungsoperator und Kopierkonstruktor zeigst?
Genau dort liegen nämlich deine Probleme. Und wenn du garkeine Datenkopie willst, musst du mit Referenzzählung arbeiten (Am leichtesten in dem du std::tr1::shared_ptr oder das boost Gegenstück verwendest; Siehe auch www.boost.org, genauer die Smartpointer-Bibliothek)Und auch Datenkappselung wäre vielleicht ein passendes Thema für dich.
Und auch new mit 0 Elementen lass mal sein...Aber grundsätzlich müsste deine Klasse die folgende Schnittstelle realisieren:
class MyClass { public: double* Data; unsigned ItemCount; MyClass(); MyClass(unsigned Size); MyClass(MyClass const & rhs); MyClass& operator=(MyClass const & rhs); ~MyClass(); MyClass Test(); } MyClass::MyClass() : Data(NULL), itemCount(0) { } MyClass::MyClass(unsigned Size) : Data(new double[Size]), ItemCount(Size) { } MyClass::~MyClass() { delete[] Data; } MyClass(MyClass const & rhs) : Data(0), ItemCount(0) { if(rhs.ItemCount > 0) { Data = new double[rhs.ItemCount]; ItemCount = rhs.ItemCount; for(unsigned m = 0; m < ItemCount; ++m) Data[m] = rhs.Data[m]; } } MyClass& operator=(MyClass const & rhs) { if(this == &rhs) return this; delete Data; Data = new double[rhs.ItemCount]; ItemCount = rhs.ItemCount; for(unsigned m = 0; m < ItemCount; ++m) Data[m] = rhs.Data[m]; return *this; } MyClass MyClass::Test() { MyClass Temp(ItemCount); for(unsigned m = 0; m < ItemCount; ++m) Temp.Data[m] = Data[m]*m; return Temp; }cu André
-
Firefighter schrieb:
Da du ja den operator= und den dtor hast, musst du dich auch an die "Big Three" halten und den copyctor noch implementieren und in dem machst du einfach das was du in deiner Testmethode angestellt hast.
Und außerdem solltest du kein Temporäres Objekt zurückgeben sondern eine Referenz.So? Warum eine Referenz in der Funktion Test?
Dir ist hoffentlich bewusst das eine Referenz als Rückgabe in der Regel einen sehr ungewünschten Effekt hat (Ich meine sowas wie ein bereits gelöschtes Objekt; Konstante Referenzen mögen hier teilweise helfen, aber auch das nicht immer)? Referenzen sind schön und gut, aber sie können eben nicht immer verwendet werden (gerade bei Rückgaben).
cu André
-
Hallo,
Ich hoffe ich habe es verstanden, somit fehlt einfach noch folgender Konstruktor:
MyClass::MyClass(const MyClass& Copy) { ItemCount = Copy.ItemCount; Data = new double[ItemCount]; for(unsigned m = 0; m < ItemCount; m++) { Data[m] = Copy.Data[m]; } }So wie ich das verstanden habe, wird bei einem return mit diesem Konstruktor eine Kopie des Objektes erzeugt das dann zurückgegeben. Werde das dann ausprobieren und hoffe, dass es klappt. Wenn ich eine Referenz zurück geben möchte, dann muss ich auch das entsprechende Objekt haben. Somit würde z.B. aus MyClass Test() --> MyClass& Test(MyClass& Temp)?
Danke und Gruss
-
Wilder schrieb:
Ich hoffe ich habe es verstanden, somit fehlt einfach noch folgender Konstruktor:
Grundsätzliche Regel: Zuweisungsoperator und Kopierkonstruktor gehören immer zusammen.
Und das mit der Referenzrückgabe ignoriere mal gefälligst in deinem Fall. Bei einer Referenzrückgabe musst du das Objekt irgendwo am Leben erhalten. Ausnahme sind hier die konstanten Referenzen die unter Umständen eine Alternative sein können (darüber gibt es in dem Forum aber genügend Informationen).
Ich würde hier, wie du es schon stehen hast, eine temporäre Variable zurück geben.
cu André
-
Vielen Dank für die Hilfe und die Antworten.
Grüsse
Wilder