Es gibt ein Objekt der Klasse QNetworkReply. Es gibt einen Steckplatz (in einem anderen Objekt), der mit seinem fertigen () Signal verbunden ist. Die Signale sind synchron (die Standardsignale). Es gibt nur einen Thread.
Irgendwann möchte ich beide Objekte loswerden. Keine Signale mehr oder irgendetwas von ihnen. Ich will, dass sie weg sind. Nun, ich dachte, ich werde verwenden
delete obj1; delete obj2;
Aber kann ich das wirklich? Die Spezifikationen für ~ QObject sagen:
Das Löschen eines QObjects, während ausstehende Ereignisse auf die Zustellung warten, kann zu einem Absturz führen.
Was sind die "ausstehenden Ereignisse"? Könnte das bedeuten, dass während ich meine anrufe delete
, bereits einige "ausstehende Ereignisse" zugestellt werden müssen und dass sie einen Absturz verursachen können und ich nicht wirklich überprüfen kann, ob es welche gibt?
Nehmen wir also an, ich rufe an:
obj1->deleteLater(); obj2->deleteLater();
Sicher sein.
Aber bin ich wirklich sicher? Das deleteLater
fügt ein Ereignis hinzu, das in der Hauptschleife behandelt wird, wenn die Steuerung dort ankommt. Kann es einige ausstehende Ereignisse (Signale) für obj1
oder obj2
bereits geben, die darauf warten, in der Hauptschleife behandelt zu werden, bevor deleteLater behandelt wird? Das wäre sehr unglücklich. Ich möchte keinen Code schreiben, der den Status "etwas gelöscht" überprüft und das eingehende Signal in allen meinen Steckplätzen ignoriert.
quelle
obj->disconnect(); obj->deleteLater();
als wäre der richtige Weg:deleteLater()
einfach ein aQDeferredDeleteEvent
an das Objekt gesendet wird, für dasdeleteLater()
aufgerufen wurde. Wenn dieses Ereignis vom QObject empfangen wird, ruft sein Ereignishandler letztendlich regulär auf,delete
was wiederum den Destruktor des QObject aufruft. Die Signalunterbrechung erfolgt erst am Ende des Destruktors. Daher würde ich vermuten, dass das QObject Slots ausführt, die von DirectConnection-Signalen aufgerufen werden, die nach dem Aufruf von,deleteLater()
aber bevor die Ereignisschleife zurückkehrt , ausgegeben werden .Antworten:
Das Löschen von QObjects ist normalerweise sicher (dh in der normalen Praxis; es kann pathologische Fälle geben, die mir atm nicht bekannt sind), wenn Sie zwei Grundregeln befolgen:
Löschen Sie niemals ein Objekt in einem Slot oder einer Methode, die direkt oder indirekt von einem (synchronen, Verbindungstyp "direkt") Signal aus dem zu löschenden Objekt aufgerufen wird. Wenn Sie beispielsweise eine Klasse Operation mit einem Signal Operation :: finish () und einem Slot Manager :: operationFinished () haben, möchten Sie das Operationsobjekt, das das Signal in diesem Slot ausgegeben hat, nicht löschen. Die Methode, die das Signal finish () ausgibt, greift möglicherweise nach der Ausgabe weiterhin auf "this" zu (z. B. auf ein Mitglied) und bearbeitet dann einen ungültigen "this" -Zeiger.
Löschen Sie niemals ein Objekt in Code, der synchron aus der Ereignisbehandlungsroutine des Objekts aufgerufen wird. Löschen Sie beispielsweise kein SomeWidget in SomeWidget :: fooEvent () oder in Methoden / Slots, die Sie von dort aus aufrufen. Das Ereignissystem arbeitet weiterhin mit dem bereits gelöschten Objekt -> Absturz.
Beides kann schwierig zu finden sein, da die Rückverfolgungen normalerweise seltsam aussehen (wie Absturz beim Zugriff auf eine POD-Mitgliedsvariable), insbesondere wenn Sie komplizierte Signal- / Slot-Ketten haben, bei denen ein Löschen mehrere Schritte nach unten erfolgen kann, das ursprünglich durch ein Signal oder ein Ereignis von ausgelöst wurde das Objekt, das gelöscht wird.
Solche Fälle sind der häufigste Anwendungsfall für deleteLater (). Es stellt sicher, dass das aktuelle Ereignis abgeschlossen werden kann, bevor das Steuerelement zur Ereignisschleife zurückkehrt, die dann das Objekt löscht. Eine andere, ich finde oft bessere Möglichkeit, die gesamte Aktion zu verschieben, indem eine Verbindung in der Warteschlange / QMetaObject :: invokeMethod (..., Qt :: QueuedConnection) verwendet wird.
quelle
Die nächsten beiden Zeilen Ihrer verwiesenen Dokumente enthalten die Antwort.
Von ~ QObject ,
Es heißt ausdrücklich, dass wir nicht aus anderen Threads löschen sollen. Da Sie eine einzelne Thread-Anwendung haben, ist das Löschen sicher
QObject
.Andernfalls, wenn Sie es in einer Multithread-Umgebung
deleteLater()
löschen müssen , verwenden Sie diese Option, um Ihre zu löschen,QObject
sobald die Verarbeitung aller Ereignisse abgeschlossen ist.quelle
Sie finden eine Antwort auf Ihre Frage zu einer der Delta-Objektregeln, in der Folgendes angegeben ist:
Fragment:
Im Allgemeinen betrachte ich Delta Object Rules als obligatorische Lektüre für jeden Qt-Entwickler. Es ist ausgezeichnetes Lesematerial.
quelle
Soweit ich weiß, ist dies hauptsächlich ein Problem, wenn die Objekte in verschiedenen Threads vorhanden sind. Oder vielleicht während Sie die Signale tatsächlich verarbeiten.
Andernfalls werden beim Löschen eines QObject zunächst alle Signale und Slots getrennt und alle ausstehenden Ereignisse entfernt. Da würde ein Aufruf zum Trennen () genügen.
quelle