Löschen von Objekten durch Signale, Eigentümer von Objekten in Signale senden, Qt
-
02-10-2019 - |
Frage
Hier, meine Signaldeklaration:
signals:
void mySignal(MyClass *);
Und wie ich verwende es:
MyClass *myObject=new myClass();
emit mySignal(myObject);
Hier kommt mein Problem: Wer zum Löschen von myObject verantwortlich ist:
-
Sender-Code, was, wenn es vor myObject löscht verwendet wird? Dangling Pointer
-
Die Schlitz-Signal verbunden, was ist, wenn es keinen Schlitz oder mehr als ein Schlitz, der mit dem Signal verbunden ist? Speicherverlust oder baumelnde Zeiger
Wie schafft Qt diese Situation in seinem Build-in-Signale? Gibt es interne Referenzzählung verwenden?
Was sind Ihre besten Praktiken?
Lösung
Sie können ein Signal mit so vielen Slots verbinden, wie Sie möchten, so sollten Sie sicherstellen, dass keine dieser Schlitze sind in der Lage, etwas zu tun würden Sie nicht wollen, dass sie mit Ihrem Objekt zu tun:
- Wenn Sie sich entscheiden, einen Zeiger als Parameter zu übergeben, dann werden Sie in den Ausgaben laufen Sie beschreiben, Speicherverwaltung - hier niemand für Sie die Arbeit, wie Sie eine Politik zu etablieren haben für mit Zuordnung / Löschung zu tun. Um einige Ideen, wie dies zu adressieren die Speicherverwaltung Regeln in dem COM Welt.
- Wenn Sie sich entscheiden, einen Parameter als Referenz zu übergeben, dann haben Sie keine Sorgen zu machen über die Speicherverwaltung, sondern nur über Schlitze zu modifizieren Ihr Objekt auf unerwartete Weise. Die ideea nicht Zeiger passieren, es sei denn man muss -. Stattdessen Referenzen verwenden, wenn Sie können
- Wenn Sie sich entscheiden, dann eine
const
Referenz zu übergeben, auf dem Verbindungstyp abhängig, QT wird den Wert des Objekts für Sie (siehe diese für einige Details) - Probleme vermeiden und nach Wert übergeben:)
Siehe auch diese Frage für einige Gedanken über Zeiger in Signale übergeben.
Andere Tipps
Für Ihre erste Frage, die Verwendung QPointer
Für Ihre zweite Frage,
Wenn ich klar verstanden, auch wenn Sie myObject
senden, Sie immer noch die Referenz hat myObject
in der Klasse, in der Sie das Signal emittiert. Dann, wie es wird ein Speicherleck oder ein baumelnden Zeiger sein? Sie können immer noch Zugriff die myObject
aus der emittierten Klasse, nicht?
Hope ist klar ..
Edit:
Von Ihre Kommentare Ich glaube, Sie sind die Freigabe / die Objekte in die Schlitze zu löschen. Nun gehe ich davon aus, Ihr Problem ist, was passiert, wenn der (Speicher Freigabe) Schlitz einmal aufgerufen wird, zweimal oder gar nicht genannt.
Sie können QPointer dafür. Von der Qt-Dokumentation
Bewacht Zeiger (QPointer
) sind nützlich, wenn Sie einen Zeiger auf eine QObject
speichern müssen, die von jemand anderem gehört, und deshalb zerstört werden könnte, während Sie noch einen Verweis auf sie halten. Sie können sicher den Zeiger auf Gültigkeit prüfen.
Ein Beispiel aus der Qt-Dokumentation selbst,
QPointer<QLabel> label = new QLabel;
label->setText("&Status:");
...
if (label)
label->show();
Die Erklärung geht weiter so ..
Wenn die QLabel in der Zwischenzeit gelöscht wird, wird das Etikett Größe 0 halten, anstatt eine ungültige Adresse, und die letzte Zeile wird nie ausgeführt werden. Hier QLabel wird Ihr MyClass
und Label ist Ihr myObject
. Und bevor es überprüft Ungültigkeit verwenden.
1): Der Absender sollte darauf achten. Wenn das Signal synchron Senden (statt der Warteschlange), ist das Objekt noch am Leben, wenn ein Empfänger die ihn empfängt. Wenn der Empfänger Bedürfnisse zu speichern, nur ein QPointer helfen würde, aber dann muss MyClass von QObject abzuleiten, die aus dem Kontext falsch aussieht. Wie auch immer, das ist eine allgemeine Lebensdauer Problem, nicht sehr Signal / Slot-spezifisch ist.
Alternativen: Verwenden Sie einen Wert Klasse und über konstante Referenz senden. Wenn MyClass Subklassen haben kann, passieren eine const QSharedPointer &
Über deleteLater: deleteLater () hilft hier nicht. Es wäre Verbindungen nicht sichere Warteschlange machen, und für direkte Verbindungen macht es keinen Unterschied. Die eine Verwendung, wo deleteLater () ins Spiel kommt, wenn der Empfänger den Sender löschen muss. Dann sollte man immer verwenden deleteLater (), so kann der Absender vervollständigen, was er tat, was sonst abstürzen würde.
In einem Wort (in Ordnung, Funktionsname) - deleteLater () :) Alle QObjects es haben. Es wird das Objekt zum Löschen markieren, und dies wird dann auf der nächsten Ereignisschleife Update passieren.