TN017: Zerstören von Fensterobjekten
In diesem Hinweis wird die Verwendung der CWnd::PostNcDestroy
Methode beschrieben. Verwenden Sie diese Methode, wenn Sie eine angepasste Zuordnung von CWnd
abgeleiteten Objekten ausführen möchten. In diesem Hinweis wird auch erläutert, warum Sie anstelle des delete
Operators ein C++-Windows-Objekt zerstören solltenCWnd::DestroyWindow
.
Wenn Sie die Richtlinien in diesem Artikel befolgen, gibt es nur wenige sauber Up-Probleme. Diese Probleme können zu Problemen führen, z. B. das Löschen/Freigeben des C++-Speichers, das Vergessen, Systemressourcen wie HWND
s freizugeben oder Objekte zu oft freizugeben.
Das Problem
Jedes Fensterobjekt (Objekt einer von ) abgeleiteten CWnd
Klasse stellt sowohl ein C++-Objekt als auch ein HWND
. C++-Objekte werden im Heap der Anwendung zugeordnet und HWND
werden vom Fenster-Manager in Systemressourcen zugewiesen. Da es mehrere Möglichkeiten gibt, ein Fensterobjekt zu zerstören, müssen wir eine Reihe von Regeln bereitstellen, die Systemressourcen oder Speicherverluste verhindern. Diese Regeln müssen auch verhindern, dass Objekte und Windows-Handles mehr als einmal zerstört werden.
Zerstörte Fenster
Im Folgenden sind die beiden zulässigen Methoden zum Zerstören eines Windows-Objekts aufgeführt:
Aufrufen
CWnd::DestroyWindow
oder die Windows-APIDestroyWindow
.Explizites Löschen mit dem
delete
Operator.
Der erste Fall ist bei weitem am häufigsten. Dieser Fall gilt auch dann, wenn Ihr Code nicht direkt aufruft DestroyWindow
. Wenn der Benutzer ein Framefenster direkt schließt, generiert diese Aktion die WM_CLOSE Nachricht, und die Standardantwort auf diese Nachricht besteht darin, aufzurufen DestroyWindow
. Wenn ein übergeordnetes Fenster zerstört wird, ruft Windows alle untergeordneten Elemente auf DestroyWindow
.
Der zweite Fall, die Verwendung des delete
Operators für Windows-Objekte, sollte selten sein. Im Folgenden sind einige Fälle aufgeführt, in denen die Verwendung delete
die richtige Wahl ist.
Automatisches sauber up mitCWnd::PostNcDestroy
Wenn das System ein Windows-Fenster zerstört, wird WM_NCDESTROY
die letzte windows-Nachricht, die an das Fenster gesendet wurde, angezeigt. Der Standardhandler CWnd
für diese Nachricht lautet CWnd::OnNcDestroy
. OnNcDestroy
wird das HWND
vom C++-Objekt getrennt und die virtuelle Funktion PostNcDestroy
aufgerufen. Einige Klassen überschreiben diese Funktion, um das C++-Objekt zu löschen.
Die Standardimplementierung von CWnd::PostNcDestroy
"does nothing", die für Fensterobjekte geeignet ist, die im Stapelframe zugeordnet sind oder in andere Objekte eingebettet sind. Dieses Verhalten eignet sich nicht für Fensterobjekte, die für die Zuordnung auf dem Heap ohne andere Objekte vorgesehen sind. Das heißt, es ist nicht für Fensterobjekte geeignet, die nicht in andere C++-Objekte eingebettet sind.
Klassen, die für die Zuordnung allein für den Heap vorgesehen sind, setzen die PostNcDestroy
Methode außer Kraft, um eine delete this;
. Diese Anweisung gibt alle Arbeitsspeicher frei, die dem C++-Objekt zugeordnet sind. Obwohl die Standarddestruktoraufrufe DestroyWindow
CWnd
andernfalls m_hWnd
nicht NULL
erfolgen, führt dieser Aufruf nicht zu unendlicher Rekursion, da der Handle getrennt und NULL
während der sauber upphase getrennt wird.
Hinweis
Das System wird in der Regel aufgerufen CWnd::PostNcDestroy
, nachdem die Windows-Nachricht WM_NCDESTROY
verarbeitet wurde, und das HWND
C++-Fensterobjekt ist nicht mehr verbunden. Das System ruft CWnd::PostNcDestroy
auch die Implementierung der meisten CWnd::Create
Aufrufe auf, wenn ein Fehler auftritt. Die Regeln für die automatische sauber up werden weiter unten in diesem Artikel beschrieben.
Auto-sauber up-Klassen
Die folgenden Klassen sind nicht für die automatische sauber up ausgelegt. Sie sind in der Regel in andere C++-Objekte oder auf dem Stapel eingebettet:
Alle standardmäßigen Windows-Steuerelemente (
CStatic
,CEdit
,CListBox
usw.).Alle untergeordneten Fenster, die direkt von
CWnd
(z. B. benutzerdefinierten Steuerelementen) abgeleitet werden.Splitterfenster (
CSplitterWnd
).Standardsteuerungsleisten (klassen abgeleitet,
CControlBar
siehe Technisches Hinweis 31 zum Aktivieren der automatischen Löschung für Steuerelementleistenobjekte).Dialoge (
CDialog
) entwickelt für modale Dialogfelder im Stapelframe.Alle Standarddialogfeld mit Ausnahme
CFindReplaceDialog
von .Die standarddialogischen Dialogfelder, die von ClassWizard erstellt wurden.
Die folgenden Klassen sind für die automatische sauber up konzipiert. Sie werden in der Regel selbst auf dem Heap zugeordnet:
Hauptrahmenfenster (direkt oder indirekt von
CFrameWnd
).Ansichtsfenster (direkt oder indirekt von
CView
).
Wenn Sie diese Regeln unterbrechen möchten, müssen Sie die PostNcDestroy
Methode in der abgeleiteten Klasse überschreiben. Wenn Sie Ihrem Kurs automatisch sauber up hinzufügen möchten, rufen Sie Ihre Basisklasse auf, und führen Sie dann eine delete this;
. Wenn Sie die automatische sauber aus Ihrer Klasse entfernen möchten, rufen Sie CWnd::PostNcDestroy
direkt anstelle der PostNcDestroy
Methode Der direkten Basisklasse auf.
Die am häufigsten verwendete Verwendung des Verhaltens der automatischen sauber up besteht darin, ein modusloses Dialogfeld zu erstellen, das für den Heap zugewiesen werden kann.
Gründe für einen Aufruf von delete
Es wird empfohlen, ein DestroyWindow
Windows-Objekt zu zerstören, entweder die C++-Methode oder die globale DestroyWindow
API.
Rufen Sie die globale DestroyWindow
API nicht auf, um ein untergeordnetes MDI-Fenster zu zerstören. Stattdessen sollten Sie die virtuelle Methode CWnd::DestroyWindow
verwenden.
Bei C++-Fensterobjekten, die keine automatische sauber up ausführen, kann die Verwendung des delete
Operators zu einem Speicherverlust führen, wenn Sie versuchen, den CWnd::~CWnd
Destruktor aufzurufenDestroyWindow
, wenn dies VTBL
nicht auf die korrekt abgeleitete Klasse verweist. Das Leck tritt auf, da das System die entsprechende Zerstörungsmethode nicht finden kann, die aufgerufen werden soll. Die Verwendung DestroyWindow
anstelle dieser delete
Probleme wird vermieden. Da dieser Fehler subtil sein kann, generiert das Kompilieren im Debugmodus die folgende Warnung, wenn Sie gefährdet sind.
Warning: calling DestroyWindow in CWnd::~CWnd
OnDestroy or PostNcDestroy in derived class will not be called
Für C++-Windows-Objekte, die automatisch sauber up ausführen, müssen Sie aufrufenDestroyWindow
. Wenn Sie den Operator direkt verwenden, benachrichtigt Sie der MFC-Diagnosespeicher-Allocator, dass Sie Arbeitsspeicher zweimal freigeben.If you use the delete
operator directly, the MFC diagnostic memory allocator will notify you're two times. Die beiden Vorkommen sind Ihr erster expliziter Aufruf und der indirekte Aufruf delete this;
in der automatischen sauber up-Implementierung von PostNcDestroy
.
Nachdem Sie ein nicht automatisch sauber up-Objekt aufgerufen DestroyWindow
haben, befindet sich das C++-Objekt weiterhin, ist aber m_hWnd
vorhandenNULL
. Nachdem Sie ein Auto-sauber up-Objekt aufgerufen DestroyWindow
haben, ist das C++-Objekt nicht mehr vorhanden und wird vom C++-Löschoperator in der Auto-sauber up-Implementierung freigegebenPostNcDestroy
.
Siehe auch
Technische Hinweise nach Nummer
Technische Hinweise nach Kategorie