Dela via


TN017: Förstöra fönsterobjekt

Den här anteckningen beskriver hur metoden används CWnd::PostNcDestroy . Använd den här metoden om du vill göra anpassad allokering av CWnd-härledda objekt. Den här anteckningen förklarar också varför du bör använda CWnd::DestroyWindow för att förstöra ett C++ Windows-objekt i stället för operatorn delete .

Om du följer riktlinjerna i den här artikeln har du få rensningsproblem. Dessa problem kan bero på problem som att glömma bort/frigöra C++-minne, glömma att frigöra systemresurser som HWNDs eller frigöra objekt för många gånger.

Problemet

Varje windows-objekt (objekt i en klass som härletts från CWnd) representerar både ett C++-objekt och ett HWND. C++-objekt allokeras i programmets heap och HWNDallokeras i systemresurser av fönsterhanteraren. Eftersom det finns flera sätt att förstöra ett fönsterobjekt måste vi tillhandahålla en uppsättning regler som förhindrar systemresurs- eller minnesläckor. Dessa regler måste också förhindra att objekt och Windows-handtag förstörs mer än en gång.

Förstöra fönster

Följande är de två tillåtna sätten att förstöra ett Windows-objekt:

  • Anropa CWnd::DestroyWindow eller Windows-API:et DestroyWindow.

  • Genom att uttryckligen radera med operatorn delete.

Det första fallet är det överlägset vanligaste. Det här fallet gäller även om din kod inte anropar DestroyWindow direkt. När användaren stänger ett ramfönster direkt genererar den här åtgärden det WM_CLOSE meddelandet, och standardsvaret på det här meddelandet är att anropa DestroyWindow. När ett överordnat fönster förstörs anropar Windows DestroyWindow för alla sina underordnade fönster.

Det andra fallet, användningen av operatorn delete på Windows-objekt, bör vara sällsynt. Följande är några fall där användning delete är rätt val.

Automatisk rensning med CWnd::PostNcDestroy

När systemet förstör ett Windows-fönster är WM_NCDESTROYdet sista Windows-meddelandet som skickas till fönstret . CWnd Standardhanteraren för meddelandet är CWnd::OnNcDestroy. OnNcDestroy kopplar bort HWND från C++-objektet och anropar den virtuella funktionen PostNcDestroy. Vissa klasser åsidosätter den här funktionen för att ta bort C++-objektet.

Standardimplementeringen av CWnd::PostNcDestroy gör ingenting, vilket är lämpligt för fönsterobjekt som allokeras på stackramen eller bäddas in i andra objekt. Det här beteendet är inte lämpligt för fönsterobjekt som är avsedda att allokeras i heapen utan några andra objekt. Med andra ord är det inte lämpligt för fönsterobjekt som inte är inbäddade i andra C++-objekt.

Klasser som är utformade för enbart allokering på heap åsidosätter PostNcDestroy metoden för att utföra en delete this;. Den här instruktionen frigör allt minne som är associerat med C++-objektet. Även om standarddestruktorn anropar CWnd om DestroyWindow inte är m_hWnd, leder det här anropet inte till oändlig rekursion eftersom handtaget kopplas bort och NULL under rensningsfasen.

Anmärkning

Systemet anropar CWnd::PostNcDestroy vanligtvis när det har bearbetat Windows-meddelandet WM_NCDESTROY och HWND och C++-fönsterobjektet är inte längre anslutna. Systemet anropar CWnd::PostNcDestroy även implementeringen av de flesta CWnd::Create anrop om fel inträffar. Reglerna för automatisk rensning beskrivs senare i den här artikeln.

Automatiska rensningsklasser

Följande klasser är inte utformade för automatisk rensning. De är vanligtvis inbäddade i andra C++-objekt eller i stacken:

  • Alla Standard Windows-kontroller (CStatic, CEdit, CListBoxoch så vidare).

  • Alla underordnade fönster som härleds direkt från CWnd (till exempel anpassade reglage).

  • Splitterfönster (CSplitterWnd).

  • Standardkontrollstaplar (klasser som härleds från CControlBar, se Technical Note 31 för aktivering av automatisk borttagning för kontrollfältsobjekt).

  • Dialogrutor (CDialog) utformade för modala dialogrutor i stackramen.

  • Alla standarddialoger utom CFindReplaceDialog.

  • Standarddialogrutorna som skapats av ClassWizard.

Följande klasser är utformade för automatisk rensning. De allokeras vanligtvis var för sig på högen.

  • Huvudramfönster (härleds direkt eller indirekt från CFrameWnd).

  • Visa fönster (härleds direkt eller indirekt från CView).

Om du vill bryta mot dessa regler måste du åsidosätta PostNcDestroy metoden i din härledda klass. Om du vill lägga till automatisk rensning i klassen anropar du basklassen och gör sedan en delete this;. Om du vill ta bort automatisk rensning från klassen anropar du CWnd::PostNcDestroy direkt i stället för metoden för PostNcDestroy din direkta basklass.

Den vanligaste användningen av att ändra beteendet för automatisk rensning är att skapa en modellös dialogruta som kan allokeras på heap.

När du ska ringa delete

Vi rekommenderar att du anropar DestroyWindow för att förstöra ett Windows-objekt, antingen C++-metoden eller det globala DestroyWindow API:et.

Anropa inte det globala DestroyWindow API:et för att stänga ett MDI-barnfönster. Du bör använda den virtuella metoden CWnd::DestroyWindow i stället.

För C++-fönsterobjekt som inte utför automatisk rensning kan användning av operatorn delete orsaka en minnesläcka när du försöker anropa DestroyWindow i CWnd::~CWnd destruktorn om VTBL den inte pekar på den korrekt härledda klassen. Läckan uppstår eftersom systemet inte kan hitta rätt destrueringsmetod att anropa. Använd DestroyWindow i stället för delete undviker dessa problem. Eftersom det här felet kan vara diskret genererar kompilering i felsökningsläge följande varning om du är i riskzonen.

Warning: calling DestroyWindow in CWnd::~CWnd
    OnDestroy or PostNcDestroy in derived class will not be called

För C++ Windows-objekt som utför automatisk rensning måste du anropa DestroyWindow. Om du använder operatorn delete direkt meddelar MFC-diagnostikminnesallokeraren att du frigör minne två gånger. De två förekomsterna är ditt första explicita anrop och det indirekta anropet till delete this; i implementeringen av automatisk rensning av PostNcDestroy.

När du anropar DestroyWindow ett icke-automatiskt rensningsobjekt kommer C++-objektet fortfarande att finnas kvar, men m_hWnd blir NULL. När du anropar DestroyWindow ett objekt för automatisk rensning är C++-objektet borta och frigörs av C++-borttagningsoperatorn i implementeringen av automatisk rensning av PostNcDestroy.

Se även

Tekniska anteckningar efter nummer
Tekniska anteckningar efter kategori