Warum verwenden offizielle Beispiele und Tutorials zur Qt-Bibliothek niemals intelligente Zeiger? Ich sehe nur new
und delete
zum Erstellen und Zerstören der Widgets.
Ich habe nach dem Grund gesucht, konnte ihn aber nicht finden, und ich sehe selbst keinen, außer aus historischen Gründen oder aus Gründen der Abwärtskompatibilität: Nicht jeder möchte, dass das Programm beendet wird, wenn ein Widget-Konstruktor ausfällt, und es über try / catch verarbeitet Blöcke sind einfach hässlich (auch wenn sie an wenigen Stellen verwendet werden). Die Tatsache, dass die Eltern-Widgets möglicherweise das Eigentum der Kinder übernehmen, erklärt mir die Sache auch nur teilweise, da Sie sie delete
auf einer bestimmten Ebene immer noch für die Eltern verwenden müssten .
main()
und automatisch erfasst wird.Antworten:
Weil Qt ein Eltern-Kind-Modell verwendet, um Qobject-Ressourcen zu verwalten. Es folgt dem Composite + Chain-of-Responsibility-Muster, das von der Ereignisverwaltung über die Speicherverwaltung, das Zeichnen, die Dateiverwaltung usw. verwendet wird.
Der Versuch, ein QObject in einem gemeinsam genutzten \ eindeutigen Zeiger zu verwenden, ist in 99% der Fälle überentwickelt .
deleteLater
direkt anrufen .Trotzdem können Sie RAII weiterhin mit Qt verwenden. Zum Beispiel verhält sich QPointer als schwache Referenz auf a
QObject
. Ich würdeQPointer<QWidget>
eher verwenden alsQWidget*
.Hinweis: Um nicht zu fanboy zu klingen, zwei Wörter: Qt + Valgrind.
quelle
deleteLater
anstatt es einfach zudelete
bearbeiten? Ich verwalte häufig Instanzen von QObject-abgeleiteten Klassen mithilfe intelligenter Zeiger. Daher habe ich zuvor nach einer Antwort darauf gesucht, um sicherzustellen, dass ich nichts Gefährliches tue, und soweit ich das beurteilen kann, gibt die Dokumentation nicht an, dass dies der Fall ist falsch zudelete
einem QObject Zeiger normal (auch wenn es sich von einem übergeordneten Objekt gehört, weil der Destruktor der Eltern Referenz wird entfernen).QObject
von einer anderen löschenQThread
. Der Destruktor vonQObject
trennt alle Signale von und zu ihm und entfernt ausstehende Ereignisse automatisch aus seiner Ereigniswarteschlange. Daher ist das Aufrufendelete
von aQObject
in Ordnung, wenn Sie dies innerhalb des Threads tun. DavondeleteLater()
abgesehen können Sie kaum etwas falsch machen, außer wenn Sie aus irgendeinem Grund eine sofortige Reinigung benötigen.Intelligente Zeiger auf Kinder
Die Smart Pointer Klassen
std::unique_ptr
undstd::shared_ptr
dienen der Speicherverwaltung. Mit einem solchen intelligenten Zeiger bedeutet, dass Sie besitzen den Zeiger. Wenn Sie jedoch einenQObject
oder einen abgeleiteten Typ mit einemQObject
übergeordneten Element erstellen , wird das Eigentum (die Verantwortung für die Bereinigung) an das übergeordnete Element übergebenQObject
. In diesem Fall sind die intelligenten Zeiger der Standardbibliothek unnötig oder sogar gefährlich, da sie möglicherweise zu einer doppelten Löschung führen können. Huch!Rohe Zeiger auf Waisenkinder
Wenn jedoch ein
QObject
(oder ein abgeleiteter Typ) auf dem Heap ohne übergeordnetesQObject
Element erstellt wird, sind die Dinge sehr unterschiedlich. In diesem Fall sollten Sie nicht nur einen Rohzeiger halten, sondern einen intelligenten Zeiger, vorzugsweise einenstd::unique_ptr
auf das Objekt. Auf diese Weise erhalten Sie Ressourcensicherheit. Wenn Sie das Objekt später einem übergeordneten Objekt übergeben,QObject
können Sie Folgendes verwendenstd::unique_ptr<T>::release()
:auto obj = std::make_unique<MyObject>(); // ... do some stuff that might throw ... QObject parentObject; obj->setParent( &parentObject ); obj.release();
Wenn das, was Sie tun, bevor Sie Ihrem Waisenkind ein Elternteil geben, eine Ausnahme auslöst, liegt ein Speicherverlust vor, wenn Sie den Rohzeiger zum Halten des Objekts verwenden. Der obige Code ist jedoch gegen ein solches Leck geschützt.
Allgemeiner gesagt
Es ist kein moderner C ++ - Rat, Rohzeiger insgesamt zu vermeiden, sondern zu vermeiden, Rohzeiger zu besitzen . Ich könnte einen weiteren modernen C ++ - Rat hinzufügen: Verwenden Sie keine intelligenten Zeiger für Objekte, die einer anderen Programmentität gehören.
quelle
Sie haben bereits Ihre eigene Frage beantwortet :
except if it's for historic reasons/backward compatibility
. Eine Bibliothek, die so groß wie QT ist, kann nicht davon ausgehen, dass jeder, der die Bibliothek verwendet, über Compiler verfügt, die C ++ 11 unterstützen.new
unddelete
sind in früheren Standards garantiert vorhanden.Wenn Sie jedoch die Unterstützung für die Verwendung intelligenter Zeiger haben, würde ich empfehlen, diese über Rohzeigern zu verwenden.
quelle
auto_ptr
, war es die richtige Entscheidung, sie nicht zu verwenden. Vor C ++ 11 gab es keine guten standardisierten Smart Pointer.QSharedPointer
undQScopedPointer
.Zusätzlich zu dem, was @Jamey gesagt hat:
Wenn Sie es geschickt gestalten, müssen Sie möglicherweise nie ein Löschen für ein Widget verwenden. Nehmen wir an, Sie haben ein Hauptfenster und erstellen ein automatisches Objekt davon und führen dieses Fenster in einer Ereignisschleife aus. Jetzt können alle Elemente in diesem Widget als untergeordnete Elemente hinzugefügt werden. Und da Sie sie als Kind direkt / indirekt zu diesem MainWindow hinzufügen, wird beim Schließen dieses Hauptfensters automatisch alles erledigt. Sie müssen lediglich sicherstellen, dass alle von Ihnen erstellten dynamischen Objekte / Widgets Kinder / Enkel des MainWindow sind. Daher ist kein explizites Löschen erforderlich.
quelle
QObject
hat ein übergeordnetes Element definiert und die baumartige Struktur des Programms ermöglicht eine recht effektive Speicherverwaltung.Die Dynamik in Qt bricht dieses schöne Ideal, z. B. das Weitergeben eines rohen Zeigers. Man kann leicht ein halten
dangling pointer
, aber das ist ein häufiges Problem bei der Programmierung.Der Qt Smart Pointer, eigentlich eine schwache Referenz, ist
QPointer<T>
und liefert einige der STL-Süßigkeiten.
Man kann auch mit
std::unique_ptr
und dergleichen mischen , aber es sollte nur für Nicht-Qt-Maschinen in Ihrem Programm verwendet werden.quelle