TN017: Zničení objektů oken
Tato poznámka popisuje použití CWnd::PostNcDestroy
metody. Tuto metodu použijte, pokud chcete provést přizpůsobené přidělení CWnd
-odvozených objektů. Tato poznámka také vysvětluje, proč byste místo operátoru měli použít CWnd::DestroyWindow
ke zničení objektu delete
systému Windows C++.
Pokud budete postupovat podle pokynů v tomto článku, budete mít několik problémů s vyčištěním. Tyto problémy můžou mít za následek problémy, jako je například zapomenutí nebo uvolnění paměti jazyka C++, zapomeňte na volné systémové prostředky, jako jsou HWND
s nebo uvolnění objektů příliš mnohokrát.
Problém
Každý objekt windows (objekt třídy odvozené ) CWnd
představuje objekt jazyka C++ i objekt HWND
. Objekty C++ jsou přiděleny v haldě aplikace a HWND
jsou přiděleny v systémových prostředcích správcem oken. Protože existuje několik způsobů, jak zničit objekt okna, musíme poskytnout sadu pravidel, která brání úniku systémového prostředku nebo paměti. Tato pravidla také musí zabránit zničení objektů a obslužných rutin Systému Windows vícekrát.
Zničení oken
Následující dva povolené způsoby zničení objektu Systému Windows:
Volání
CWnd::DestroyWindow
nebo rozhraní APIDestroyWindow
systému Windows .Explicitní odstranění pomocí operátoru
delete
První případ je zdaleka nejběžnější. Tento případ platí i v případě, že váš kód nevolá DestroyWindow
přímo. Když uživatel přímo zavře okno rámce, tato akce vygeneruje WM_CLOSE zprávu a výchozí odpověď na tuto zprávu je volání DestroyWindow
. Když je nadřazené okno zničeno, systém Windows volá DestroyWindow
všechny jeho podřízené položky.
Druhý případ, použití operátoru delete
na objektech Windows, by mělo být vzácné. Tady jsou některé případy, kdy je použití delete
správnou volbou.
Automatické vyčištění pomocí CWnd::PostNcDestroy
Když systém zničí okno systému Windows, poslední zpráva systému Windows poslaná do okna je WM_NCDESTROY
. Výchozí CWnd
obslužná rutina pro tuto zprávu je CWnd::OnNcDestroy
. OnNcDestroy
odpoje od HWND
objektu C++ a zavolá virtuální funkci PostNcDestroy
. Některé třídy tuto funkci přepíší, aby se odstranil objekt C++.
Výchozí implementace CWnd::PostNcDestroy
nedělá nic, což je vhodné pro objekty okna, které jsou přiděleny na rámec zásobníku nebo vložené v jiných objektech. Toto chování není vhodné pro objekty oken navržené pro přidělení haldy bez jakýchkoli jiných objektů. Jinými slovy, není vhodné pro objekty okna, které nejsou vloženy do jiných objektů jazyka C++.
Třídy určené pro přidělení samotné haldy přepíší PostNcDestroy
metodu delete this;
k provedení . Tento příkaz uvolní veškerou paměť přidruženou k objektu C++. I když výchozí CWnd
destruktor volá DestroyWindow
, pokud m_hWnd
není NULL
, toto volání nezpůsobí nekonečné rekurze, protože popisovač bude odpojen a NULL
během fáze čištění.
Poznámka
Systém obvykle volá poté CWnd::PostNcDestroy
, co zpracuje zprávu systému Windows WM_NCDESTROY
a HWND
objekt okna C++ již nejsou připojeny. Systém bude také volat CWnd::PostNcDestroy
při implementaci většiny CWnd::Create
volání, pokud dojde k selhání. Pravidla automatického čištění jsou popsána dále v tomto článku.
Třídy automatického čištění
Následující třídy nejsou určené pro automatické vyčištění. Obvykle se vkládají do jiných objektů C++ nebo do zásobníku:
Všechny standardní ovládací prvky Systému Windows (
CStatic
,CEdit
,CListBox
atd.)Všechna podřízená okna odvozená přímo z
CWnd
(například vlastních ovládacích prvků).Rozdělovačová okna (
CSplitterWnd
).Výchozí řídicí pruhy (třídy odvozené z
CControlBar
, viz Technická poznámka 31 pro povolení automatického odstranění pro objekty řídicího pruhu).Dialogy (
CDialog
) navržené pro modální dialogy v rámci zásobníkuVšechny standardní dialogy s výjimkou
CFindReplaceDialog
.Výchozí dialogy vytvořené pomocí TřídyWizard.
Následující třídy jsou navržené pro automatické vyčištění. Obvykle se přidělují sami na haldě:
Okna hlavního rámu (odvozená přímo nebo nepřímo z
CFrameWnd
).Zobrazit okna (odvozená přímo nebo nepřímo z
CView
).
Pokud chcete tato pravidla přerušit, musíte přepsat metodu PostNcDestroy
v odvozené třídě. Pokud chcete do třídy přidat automatické vyčištění, zavolejte základní třídu a pak udělejte .delete this;
Pokud chcete z třídy odebrat automatické vyčištění, volejte CWnd::PostNcDestroy
přímo místo PostNcDestroy
metody přímé základní třídy.
Nejběžnějším použitím změny chování automatického čištění je vytvoření bezmodální dialogové okno, které lze přidělit na haldě.
Kdy zavolat delete
Doporučujeme volat DestroyWindow
, abyste zničili objekt Windows, buď metodu C++, nebo globální DestroyWindow
rozhraní API.
Nevolejte globální DestroyWindow
rozhraní API ke zničení podřízeného okna MDI. Místo toho byste měli použít virtuální metodu CWnd::DestroyWindow
.
U objektů okna C++, které neprovádějí automatické vyčištění, může použití operátoru delete
způsobit nevracení paměti při pokusu CWnd::~CWnd
o volání DestroyWindow
v destruktoru, pokud VTBL
neodkazuje na správnou odvozenou třídu. K úniku dochází, protože systém nemůže najít odpovídající metodu zničení, která se má volat. Místo DestroyWindow
toho, abyste delete
se těmto problémům vyhnuli, použijte. Protože tato chyba může být malá, kompilace v režimu ladění vygeneruje následující upozornění, pokud jste ohroženi.
Warning: calling DestroyWindow in CWnd::~CWnd
OnDestroy or PostNcDestroy in derived class will not be called
U objektů systému Windows C++, které provádějí automatické vyčištění, je nutné volat DestroyWindow
. Pokud operátor použijete delete
přímo, alokátor diagnostické paměti MFC vás upozorní, že uvolníte paměť dvakrát. Dva výskyty jsou vaše první explicitní volání a nepřímé volání delete this;
v implementaci PostNcDestroy
automatického vyčištění .
Po volání DestroyWindow
objektu bez automatického vyčištění bude objekt C++ stále kolem, ale m_hWnd
bude NULL
. Po volání DestroyWindow
objektu automatického vyčištění bude objekt C++ pryč, uvolněn operátorem odstranění jazyka C++ v implementaci automatického PostNcDestroy
vyčištění .
Viz také
Technické poznámky podle čísla
Technické poznámky podle kategorie