이 노트에서는 CWnd::PostNcDestroy
메서드 사용에 대해 설명합니다. 파생 개체의 CWnd
사용자 지정 할당을 수행하려면 이 메서드를 사용합니다. 이 설명에서는 왜 C++ Windows 개체를 삭제하는 데 CWnd::DestroyWindow
을 사용해야 하며, delete
연산자를 대신 사용하지 말아야 하는지를 설명합니다.
지침을 따르면 정리 문제가 거의 발생하지 않습니다. 이러한 문제는 C++ 메모리를 삭제/해제하는 것을 잊거나, s와 같은 HWND
시스템 리소스를 해제하지 않거나, 개체를 너무 많이 해제하는 등의 문제로 인해 발생할 수 있습니다.
문제
각 windows 객체(파생 클래스 CWnd
의 객체)는 C++ 객체와 HWND
객체를 나타냅니다. C++ 개체는 애플리케이션의 힙에 할당되며 HWND
창 관리자가 시스템 리소스에 할당합니다. 창 개체를 삭제하는 방법에는 여러 가지가 있으므로 시스템 리소스 또는 메모리 누수 방지 규칙 집합을 제공해야 합니다. 또한 이러한 규칙은 개체와 Windows 핸들이 두 번 이상 제거되지 않도록 해야 합니다.
창문을 부수기
다음은 Windows 개체를 삭제하는 두 가지 허용된 방법입니다.
호출
CWnd::DestroyWindow
또는 Windows APIDestroyWindow
.연산자를 사용하여 명시적으로 삭제합니다
delete
.
첫 번째 사례는 지금까지 가장 일반적입니다. 이 사례는 코드가 직접 호출 DestroyWindow
하지 않는 경우에도 적용됩니다. 사용자가 프레임 창을 직접 닫으면 이 작업은 WM_CLOSE 메시지를 생성하고 이 메시지에 대한 기본 응답은 호출 DestroyWindow
하는 것입니다. 부모 창이 제거되면 Windows는 모든 자식에게 대해 DestroyWindow
를 호출합니다.
두 번째 경우, Windows 개체에서 연산자를 delete
사용하는 경우는 드물어야 합니다. 다음은 사용 delete
이 올바른 선택인 경우입니다.
CWnd::PostNcDestroy
를 사용하여 자동 정리
시스템에서 Windows 창을 삭제하면 창으로 전송된 마지막 Windows 메시지는 다음과 같습니다 WM_NCDESTROY
. 해당 메시지의 기본 CWnd
처리기는 .입니다 CWnd::OnNcDestroy
.
OnNcDestroy
는 C++ 객체에서 HWND
를 분리하고 가상 함수 PostNcDestroy
를 호출합니다. 일부 클래스는 이 함수를 재정의하여 C++ 개체를 삭제합니다.
기본 구현 CWnd::PostNcDestroy
은 아무 작업도 수행하지 않습니다. 이는 스택 프레임에 할당되거나 다른 개체에 포함된 창 개체에 적합합니다. 이 동작은 다른 개체가 없는 힙에서 할당하도록 설계된 창 개체에는 적합하지 않습니다. 즉, 다른 C++ 개체에 포함되지 않은 창 개체에는 적합하지 않습니다.
힙에서만 할당되도록 설계된 클래스는 PostNcDestroy
메서드를 재정의하여 delete this;
을 수행합니다. 이 문은 C++ 개체와 연결된 모든 메모리를 해제합니다. 기본 CWnd
소멸자가 DestroyWindow
가 m_hWnd
이 아닐 경우 NULL
을(를) 호출하지만, 정리 단계 중에 핸들이 분리되고 NULL
이(가) 수행되어 이 호출이 무한 재귀로 이어지지는 않습니다.
비고
시스템은 일반적으로 Windows CWnd::PostNcDestroy
메시지 처리가 완료된 후 WM_NCDESTROY
를 호출하며, HWND
C++ 창 개체는 더 이상 연결되지 않습니다. 오류가 발생하면 시스템은 대부분의 CWnd::PostNcDestroy
호출 구현에서 CWnd::Create
를 호출합니다. 자동 정리 규칙은 이 문서의 뒷부분에 설명되어 있습니다.
자동 정리 클래스
다음 클래스는 자동 정리용으로 설계되지 않았습니다. 일반적으로 다른 C++ 개체 또는 스택에 포함됩니다.
모든 표준 Windows 컨트롤(
CStatic
,CEdit
,CListBox
등).직접
CWnd
파생된 자식 창(예: 사용자 지정 컨트롤)이 있는 경우.분할 창(
CSplitterWnd
)기본 컨트롤 막대(파생된
CControlBar
클래스, 컨트롤 막대 개체에 대해 자동 삭제를 사용하도록 설정하려면 Technical Note 31 참조).스택 프레임의 모달 대화용으로 설계된 대화 상자(
CDialog
)입니다.CFindReplaceDialog
를 제외한 모든 표준 대화 상자ClassWizard에서 만든 기본 대화 상자입니다.
다음 클래스는 자동 정리를 위해 설계되었습니다. 일반적으로 힙에 별도로 자체적으로 할당됩니다.
주 프레임 창(직접 또는 간접적으로 파생된
CFrameWnd
에서).창 보기(
CView
에서 직접 또는 간접적으로 파생됨)
이러한 규칙을 위반하려면, 파생 클래스에서 PostNcDestroy
메서드를 재정의해야 합니다. 클래스에 자동 정리 기능을 추가하려면 기본 클래스를 호출한 다음 delete this;
을 실행하세요. 클래스에서 자동 정리를 제거하려면 직접 CWnd::PostNcDestroy
를 호출하고, 직접 기본 클래스의 PostNcDestroy
메서드를 사용하지 마세요.
자동 정리 동작을 변경하는 가장 일반적인 용도는 힙에 할당할 수 있는 모덜리스 대화 상자를 만드는 것입니다.
호출 시기 delete
Windows 개체를 파괴하기 위해 DestroyWindow
을 호출하는 것을 권장하며, C++ 메서드 또는 전역 DestroyWindow
API를 사용할 수 있습니다.
MDI 자식 창을 삭제하기 위해 전역 DestroyWindow
API를 호출하지 마세요. 대신 가상 메서드 CWnd::DestroyWindow
를 사용해야 합니다.
자동 정리를 수행하지 않는 C++ Window 객체의 경우, 올바르게 파생된 클래스를 가리키지 않는다면 delete
소멸자에서 DestroyWindow
를 호출할 때 CWnd::~CWnd
연산자를 사용하면 메모리 누수가 발생할 수 있습니다. 시스템이 호출할 적절한 삭제 방법을 찾을 수 없기 때문에 누수가 발생합니다.
DestroyWindow
를 사용하면 delete
대신 이러한 문제를 방지할 수 있습니다. 이 오류는 미묘할 수 있으므로 디버그 모드에서 컴파일하면 위험에 처한 경우 다음 경고가 생성됩니다.
Warning: calling DestroyWindow in CWnd::~CWnd
OnDestroy or PostNcDestroy in derived class will not be called
자동 정리를 수행하는 C++ Windows 개체의 경우 호출 DestroyWindow
해야 합니다. 연산자를 delete
직접 사용하는 경우 MFC 진단 메모리 할당자는 메모리를 두 번 해제하고 있음을 알립니다. 두 가지 발생은 첫 번째 명시적 호출과 delete this;
의 자동 정리 구현에서 PostNcDestroy
에 대한 간접 호출입니다.
비자동 정리 개체에서 DestroyWindow
를 호출한 후에도 C++ 개체는 여전히 존재하지만, m_hWnd
는 NULL
로 될 것입니다. 자동 정리 개체를 호출 DestroyWindow
하면 C++ 개체가 사라집니다. 이 개체는 자동 정리 구현 PostNcDestroy
에서 C++ delete 연산자에 의해 해제됩니다.