Welchen Smartpointer verwenden?
-
Kenne mich mit Smart Pointer noch nicht gut aus. Deshalb meine Frage, ob es möglich ist mit der Kopie einer Pointers (Form) den Speicher von (Dreieck) freizugeben?
Ist das mit Smartpointern oder einer Kombination aus Smartpointern und RAW-Pointer möglich? "Dreieck" sollte auf jeden Fall über einen Smartpointer erstellt werden. "Form" darf auch ein RAW-Pointer sein.
Soweit ich weiß, ist bei unique_ptr keine Kopie des Pointers möglich, oder?
-
Mit unique_ptr + RAW Pointer geht das. Ob es sinnvoll ist, steht auf einem anderen Blatt.
-
manni66 schrieb:
Mit unique_ptr + RAW Pointer geht das. Ob es sinnvoll ist, steht auf einem anderen Blatt.
class CForm {};
class CDreieck : public CForm {};std::unique_ptr<CDreieck>Dreieck;
Dreieck = std::make_unique<CDreieck>();CForm* Form = Dreieck.get();
delete Form;Hallo manni66,
meinst Du so? 'delete Form' sieht irgendwie brutal aus - da meckert der Compiler auch beim beenden des Programms: Debug Assertion failed - 'ValidHeapPointer(block)'.Wie wird es richtig gemacht?
-
Ich glaube, die Frage, die wir lieber beantworten sollten, lautet: Warum willst du das überhaupt so machen? Vielleicht ist der Ansatz schon falsch.
Zum Beispiel stellt sich doch die Frage, was nach der Zuweisung
Form = Dreieck;mit Dreieck passieren soll - greift noch irgendjemand darauf zu und wenn ja, wie lange? Diese Frage stellt sich auch später noch einmal, wenn du den Speicher via Form freigeben willst. Was ist dann mit Dreieck?
-
So natürlich nicht! Es wird zweimal gelöscht.
Erkläre, was du erreichen willst.
-
Danke für die Hinweise meinen Ansatz einmal zu überprüfen. Es lag wirklich an einem Denkfehler - falscher Reihenfolge.
1. Abgeleitete Klassen sollen über einen Member Basisklassenzeiger aufgerufen werden. Dabei soll immer nur eine Instanz aktiv sein.
2. Um unfangreiches Casting zu vermeiden wird ein Zeiger auf die abgeleitete Klasse benötigt.Ich hatte nun Punkt 2 über eine unique_ptr Instanz erzeugt und dann darauf einen Basisklassenzeiger gesetzt. Mit dem ich wiederum den Speicher der abgeleiteten Klasse freigeben wollte.

Viel einfacher ist aber eine unique_ptr Instanz des Basisklassenzeigers auf die abgeleitete Klasse zu erzeugen. Und dann einen RAW Pointer der abgeleiteten Klasse darauf zu setzen, um umfangreiches Casting zu ersparen.
class CForm {};
class CDreieck : public CForm {};
class CQuadrat : public CForm {};std::unique_ptr<CForm>form;
form.reset(new CDreieck()); // Basisklassenzeiger zum Ausführen überladener Funktionen
CDreieck *dreieck = static_cast<CDreieck*>form.get(); // RAW Zeiger für Menühandlingform.reset(new CQuadrat()); // Basisklassenzeiger zum Ausführen überladener Funktionen
CQuadrat *quadrat = static_cast<CQuadrat*>form.get(); // RAW Zeiger für Menühandling
usw.Danke an alle für die Hilfe!
-
mireiner schrieb:
class CForm {};
class CDreieck : public CForm {};
class CQuadrat : public CForm {};std::unique_ptr<CForm>form;
form.reset(new CDreieck()); // Basisklassenzeiger zum Ausführen überladener Funktionen
CDreieck *dreieck = static_cast<CDreieck*>form.get(); // RAW Zeiger für Menühandlingform.reset(new CQuadrat()); // Basisklassenzeiger zum Ausführen überladener Funktionen
CQuadrat *quadrat = static_cast<CQuadrat*>form.get(); // RAW Zeiger für Menühandling
usw.Danke an alle für die Hilfe!
Das ist, sagen wir mal suboptimal, wenn du für jeden konkreten Typen wieder einen downcast machst. Kannst du die benötigte Funktionalität (zB fürs Menühandling) nicht in die Basisklasse verlagern? Oder als Interface anbieten?
Ansonsten gibt es noch das Visitor Pattern, um verschiedene Funktionen in Abhängigkeit des konketen Typs zu implementieren, ohne eine cast-Kaskade machen zu müssen.Oder du stellst die Reihenfolge deiner Anweisungen etwas um:
shared_ptr<Quadrat> q = make_shared<Quadrat>(); do_something( q ); form = q;Edit:
Wann genau und wie oft brauchst du denn das konkrete Objekt. Nur ein Mal bei Erstellung oder immer wieder zwischendurch?
-
DocShoe schrieb:
Das ist, sagen wir mal suboptimal, wenn du für jeden konkreten Typen wieder einen downcast machst. Kannst du die benötigte Funktionalität (zB fürs Menühandling) nicht in die Basisklasse verlagern? Oder als Interface anbieten?
Ansonsten gibt es noch das Visitor Pattern, um verschiedene Funktionen in Abhängigkeit des konketen Typs zu implementieren, ohne eine cast-Kaskade machen zu müssen.Oder du stellst die Reihenfolge deiner Anweisungen etwas um:
shared_ptr<Quadrat> q = make_shared<Quadrat>(); do_something( q ); form = q;Edit:
Wann genau und wie oft brauchst du denn das konkrete Objekt. Nur ein Mal bei Erstellung oder immer wieder zwischendurch?Das ganze befindet sich in einem Qt GUI Programm, wo bestimmte Strukturen vorgegeben sind, wie die Paint() Funktion und die Menüeinsprung Funktionen.
Vom User können ca. 15 abgeleitete Objekte dynamisch erzeugt und gewechselt, bzw. gelöscht werden. Die Zeiger sind aber als Member Zeigervariablen in der umschließenden GUI Klasse (QMainWindow) angelegt. Letztere beleibt während der gesammten Laufzeit erhalten.
Jede abgeleitete Klasse hat ca. 4-10 Parameter, die über Menükommandos geändert werden können. Zuviel um es in der Basisklasse unterzubringen.
Spricht denn generell etwas gegen downcasting? Das geschieht ja nur einmalig bei der Erzeugung eines Objekts in einer Menüfunktion. Mit dem daraus gewonnenen RAW-Pointer kann das Objekt dann während seiner Lebzeit beliebig oft über Menükommandos verändert werden. Die Menükommandos sind in keiner Weise Laufzeit kritisch.
-
mireiner schrieb:
Vom User können ca. 15 abgeleitete Objekte dynamisch erzeugt und gewechselt, bzw. gelöscht werden. Die Zeiger sind aber als Member Zeigervariablen in der umschließenden GUI Klasse (QMainWindow) angelegt. Letztere beleibt während der gesammten Laufzeit erhalten.
Jede abgeleitete Klasse hat ca. 4-10 Parameter, die über Menükommandos geändert werden können. Zuviel um es in der Basisklasse unterzubringen.
Spricht denn generell etwas gegen downcasting? Das geschieht ja nur einmalig bei der Erzeugung eines Objekts in einer Menüfunktion. Mit dem daraus gewonnenen RAW-Pointer kann das Objekt dann während seiner Lebzeit beliebig oft über Menükommandos verändert werden. Die Menükommandos sind in keiner Weise Laufzeit kritisch.
Warum soll sich die GUI um die Menükommandos zum Verändern des jeweiligen Objektes kümmern? Die aufgerufenen Funktionen sind doch dann "spezielle" Member des Objektes, oder sehe ich das falsch?
Lösung:
Die Objekte von QObject ableiten (oder direkt die Basisklasse) und die speziellen Funktionen in den abgeleteten Klassen als SLOTS deklarieren. Memberfunktion virtual QList<QAction> menuKommandos()* in die Basisklasse und bei einem reset die alten actions aus dem Menü entfernen und durch die neuen ersetzen. Die actions werden in der abgeleiteten Klassen in menuKommandos() erzeugt und mit den passenden SLOTS connect()ed.
-
Cantonator schrieb:
Lösung:
Die Objekte von QObject ableiten (oder direkt die Basisklasse) und die speziellen Funktionen in den abgeleteten Klassen als SLOTS deklarieren. Memberfunktion virtual QList<QAction> menuKommandos()* in die Basisklasse und bei einem reset die alten actions aus dem Menü entfernen und durch die neuen ersetzen. Die actions werden in der abgeleiteten Klassen in menuKommandos() erzeugt und mit den passenden SLOTS connect()ed.Für einen Qt Anfänger wie mich, klingt das erst einmal sehr komplex. Werde es in Ruhe einmal durchdenken. Danke für diesen Lösungvorschlag.