Freigeben über


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 CWndabgeleiteten 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 Bereinigungsprobleme. Diese Probleme können zu Problemen führen, z. B. das Löschen/Freigeben des C++-Speichers, das Vergessen, Systemressourcen wie HWNDs freizugeben oder Objekte zu oft freizugeben.

Das Problem

Jedes Fensterobjekt (Objekt einer von ) abgeleiteten CWndKlasse stellt sowohl ein C++-Objekt als auch ein HWND. C++-Objekte werden im Heap der Anwendung zugeordnet und HWNDwerden 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-API DestroyWindow.

  • 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.

Automatische Bereinigung mit CWnd::PostNcDestroy

Wenn das System ein Windows-Fenster zerstört, wird WM_NCDESTROYdie 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 PostNcDestroyaufgerufen. 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 DestroyWindowCWnd andernfalls m_hWnd nicht NULLerfolgen, führt dieser Aufruf nicht zu unendlicher Rekursion, da der Handle getrennt und NULL während der Bereinigungsphase 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 Bereinigung werden weiter unten in diesem Artikel beschrieben.

Automatische Bereinigungsklassen

Die folgenden Klassen sind nicht für die automatische Bereinigung konzipiert. Sie sind in der Regel in andere C++-Objekte oder auf dem Stapel eingebettet:

  • Alle standardmäßigen Windows-Steuerelemente (CStatic, CEdit, CListBoxusw.).

  • Alle untergeordneten Fenster, die direkt von CWnd (z. B. benutzerdefinierten Steuerelementen) abgeleitet werden.

  • Splitterfenster (CSplitterWnd).

  • Standardsteuerungsleisten (klassen abgeleitet, CControlBarsiehe 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 CFindReplaceDialogvon .

  • Die standarddialogischen Dialogfelder, die von ClassWizard erstellt wurden.

Die folgenden Klassen sind für die automatische Bereinigung 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. Rufen Sie die Basisklasse auf, um Ihrem Kurs die automatische Bereinigung hinzuzufügen, und führen Sie dann eine delete this;. Um die automatische Bereinigung aus Ihrer Klasse zu entfernen, rufen Sie direkt anstelle der PostNcDestroy Methode Der direkten Basisklasse aufCWnd::PostNcDestroy.

Die am häufigsten verwendete Verwendung des Verhaltens der automatischen Bereinigung besteht darin, ein modusloses Dialogfeld zu erstellen, das für den Heap zugewiesen werden kann.

Wann wird angerufen? 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 Bereinigung durchführen, kann die Verwendung des delete Operators einen Speicherverlust verursachen, wenn Sie versuchen, den CWnd::~CWnd Destruktor aufzurufenDestroyWindow, wenn dies VTBL nicht auf die ordnungsgemäß 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 die automatische Bereinigung ausführen, müssen Sie aufrufen DestroyWindow. 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 Bereinigungsimplementierung von PostNcDestroy.

Nachdem Sie ein Nicht-Auto-Bereinigungsobjekt aufgerufen DestroyWindow haben, befindet sich das C++-Objekt weiterhin, ist aber m_hWnd vorhanden NULL. Nachdem Sie ein AutoBereinigungsobjekt aufgerufen DestroyWindow haben, ist das C++-Objekt nicht mehr vorhanden, das vom C++-Löschoperator in der Automatischen Bereinigungsimplementierung freigegeben PostNcDestroywird.

Siehe auch

Technische Hinweise nach Nummer
Technische Hinweise nach Kategorie