TN017: Niszczenie obiektów okien
Ta uwaga opisuje użycie CWnd::PostNcDestroy
metody . Użyj tej metody, jeśli chcesz dostosować alokację CWnd
obiektów pochodnych. W tej notatce wyjaśniono również, dlaczego należy użyć CWnd::DestroyWindow
polecenia w celu zniszczenia obiektu systemu Windows w języku C++ zamiast delete
operatora.
Jeśli zastosujesz się do wytycznych opisanych w tym artykule, będziesz mieć kilka problemów z czyszczeniem. Te problemy mogą wynikać z problemów, takich jak zapominanie o usuwaniu/zwalnianiu pamięci C++, zapominaniu o zwalnianiu zasobów systemowych, takich jak HWND
s, lub zwalnianiu obiektów zbyt wiele razy.
Problem
Każdy obiekt systemu Windows (obiekt klasy pochodnej z CWnd
) reprezentuje zarówno obiekt C++, jak HWND
i obiekt . Obiekty języka C++ są przydzielane w stercie aplikacji i HWND
są przydzielane w zasobach systemowych przez menedżera okien. Ponieważ istnieje kilka sposobów zniszczenia obiektu okna, musimy podać zestaw reguł, które uniemożliwiają przecieki zasobów systemowych lub pamięci. Te reguły muszą również uniemożliwić zniszczenie obiektów i dojść systemu Windows więcej niż jeden raz.
Niszczenie okien
Poniżej przedstawiono dwa dozwolone sposoby zniszczenia obiektu systemu Windows:
Wywoływanie
CWnd::DestroyWindow
interfejsu API systemu Windows lub interfejsu APIDestroyWindow
systemu Windows.Jawne usuwanie za pomocą
delete
operatora .
Pierwszy przypadek jest zdecydowanie najbardziej typowy. Ten przypadek ma zastosowanie nawet wtedy, gdy kod nie wywołuje DestroyWindow
się bezpośrednio. Gdy użytkownik zamyka okno ramki bezpośrednio, ta akcja generuje komunikat WM_CLOSE, a domyślną odpowiedzią na ten komunikat jest wywołanie metody DestroyWindow
. Gdy okno nadrzędne zostanie zniszczone, system Windows wywołuje DestroyWindow
wszystkie jego elementy podrzędne.
Drugi przypadek, użycie delete
operatora w obiektach systemu Windows, powinno być rzadkie. Poniżej przedstawiono niektóre przypadki, w których użycie delete
jest właściwym wyborem.
Automatyczne czyszczenie za pomocą polecenia CWnd::PostNcDestroy
Gdy system zniszczy okno systemu Windows, ostatnim komunikatem systemu Windows wysłanym do okna jest WM_NCDESTROY
. Domyślną CWnd
procedurą obsługi tego komunikatu jest CWnd::OnNcDestroy
. OnNcDestroy
spowoduje odłączenie HWND
obiektu C++ i wywoła funkcję PostNcDestroy
wirtualną . Niektóre klasy zastępują tę funkcję, aby usunąć obiekt C++.
Domyślna implementacja CWnd::PostNcDestroy
nic nie robi, co jest odpowiednie dla obiektów okien przydzielonych na ramce stosu lub osadzonych w innych obiektach. To zachowanie nie jest odpowiednie dla obiektów okien przeznaczonych do alokacji na stercie bez żadnych innych obiektów. Innymi słowy, nie jest to odpowiednie dla obiektów okien, które nie są osadzone w innych obiektach języka C++.
Klasy przeznaczone tylko do alokacji na stercie przesłaniają PostNcDestroy
metodę delete this;
w celu wykonania metody . Ta instrukcja zwolni wszelkie pamięci skojarzone z obiektem C++. Mimo że domyślne CWnd
wywołania DestroyWindow
destruktora, jeśli m_hWnd
nie NULL
jest , to wywołanie nie prowadzi do nieskończonej rekursji, ponieważ uchwyt zostanie odłączony i NULL
w fazie oczyszczania.
Uwaga
System zwykle wywołuje CWnd::PostNcDestroy
po przetwarzaniu komunikatu systemu Windows WM_NCDESTROY
, a HWND
obiekt okna C++ nie jest już połączony. System wywoła również CWnd::PostNcDestroy
w implementacji większości CWnd::Create
wywołań, jeśli wystąpi awaria. Reguły automatycznego czyszczenia zostały opisane w dalszej części tego artykułu.
Klasy automatycznego czyszczenia
Następujące klasy nie są przeznaczone do automatycznego czyszczenia. Są one zwykle osadzone w innych obiektach języka C++ lub na stosie:
Wszystkie standardowe kontrolki systemu Windows (
CStatic
,CEdit
,CListBox
i tak dalej).Wszystkie okna podrzędne pochodzące bezpośrednio z
CWnd
(na przykład kontrolki niestandardowe).Okna podziału (
CSplitterWnd
).Domyślne paski sterowania (klasy pochodzące z
CControlBar
programu można znaleźć w temacie Technical Note 31 for enabling auto-delete for control bar objects (Informacje techniczne 31 dotyczące włączania automatycznego usuwania dla obiektów paska sterowania).Okna dialogowe (
CDialog
) przeznaczone dla modalnych okien dialogowych na ramce stosu.Wszystkie standardowe okna dialogowe z wyjątkiem
CFindReplaceDialog
.Domyślne okna dialogowe utworzone przez klasę ClassWizard.
Następujące klasy są przeznaczone do automatycznego czyszczenia. Są one zwykle przydzielane przez siebie na stercie:
Główne okna ramowe (pochodzące bezpośrednio lub pośrednio z
CFrameWnd
systemu ).Wyświetl okna (pochodzące bezpośrednio lub pośrednio z
CView
elementu ).
Jeśli chcesz przerwać te reguły, musisz zastąpić metodę PostNcDestroy
w klasie pochodnej. Aby dodać automatyczne czyszczenie do klasy, wywołaj klasę bazową, a następnie wykonaj polecenie delete this;
. Aby usunąć automatyczne czyszczenie z klasy, wywołaj CWnd::PostNcDestroy
metodę bezpośrednio zamiast PostNcDestroy
metody bezpośredniej klasy bazowej.
Najczęstszym zastosowaniem zmiany zachowania automatycznego czyszczenia jest utworzenie bez moderowego okna dialogowego, które można przydzielić na stercie.
Kiedy należy zadzwonić delete
Zalecamy wywołanie DestroyWindow
metody w celu zniszczenia obiektu systemu Windows , metody C++ lub globalnego DestroyWindow
interfejsu API.
Nie należy wywoływać globalnego DestroyWindow
interfejsu API w celu zniszczenia okna podrzędnego MDI. Zamiast tego należy użyć metody CWnd::DestroyWindow
wirtualnej.
W przypadku obiektów okna języka C++, które nie wykonują automatycznego czyszczenia, użycie delete
operatora może spowodować przeciek pamięci podczas próby wywołania DestroyWindow
w CWnd::~CWnd
destruktora, jeśli VTBL
klasa nie wskazuje poprawnie pochodnej klasy. Wyciek występuje, ponieważ system nie może odnaleźć odpowiedniej metody destroy do wywołania. Używanie DestroyWindow
zamiast unikać delete
tych problemów. Ponieważ ten błąd może być subtelny, kompilowanie w trybie debugowania spowoduje wygenerowanie następującego ostrzeżenia, jeśli jest zagrożone.
Warning: calling DestroyWindow in CWnd::~CWnd
OnDestroy or PostNcDestroy in derived class will not be called
W przypadku obiektów systemu Windows w języku C++, które wykonują automatyczne oczyszczanie, należy wywołać metodę DestroyWindow
. Jeśli używasz operatora bezpośrednio, alokator pamięci diagnostycznej delete
MFC powiadomi Cię o dwukrotnym zwalnianiu pamięci. Dwa wystąpienia to pierwsze jawne wywołanie i wywołanie pośrednie metody delete this;
w implementacji automatycznego oczyszczania elementu PostNcDestroy
.
Po wywołaniu DestroyWindow
obiektu nieautomaktywnego oczyszczania obiekt języka C++ będzie nadal znajdować się w pobliżu, ale m_hWnd
będzie to NULL
. Po wywołaniu DestroyWindow
obiektu automatycznego oczyszczania obiekt języka C++ zostanie usunięty, zwolniony przez operator usuwania języka C++ w implementacji PostNcDestroy
automatycznego oczyszczania elementu .
Zobacz też
Uwagi techniczne według numeru
Uwagi techniczne według kategorii