Udostępnij za pośrednictwem


TN017: Niszczenie obiektów okien

Ta uwaga opisuje użycie CWnd::PostNcDestroy metody . Użyj tej metody, jeśli chcesz dostosować alokację CWndobiektó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 HWNDs, lub zwalnianiu obiektów zbyt wiele razy.

Problem

Każdy obiekt systemu Windows (obiekt klasy pochodnej z CWnd) reprezentuje zarówno obiekt C++, jak HWNDi obiekt . Obiekty języka C++ są przydzielane w stercie aplikacji i HWNDsą 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 API DestroyWindowsystemu 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ę PostNcDestroywirtualną . 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 NULLjest , 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, CListBoxi 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 CControlBarprogramu 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 CFrameWndsystemu ).

  • Wyświetl okna (pochodzące bezpośrednio lub pośrednio z CViewelementu ).

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 PostNcDestroyautomatycznego oczyszczania elementu .

Zobacz też

Uwagi techniczne według numeru
Uwagi techniczne według kategorii