다음을 통해 공유


TN017: 창 개체 삭제

이 노트에서는 CWnd::PostNcDestroy 메서드 사용에 대해 설명합니다. 파생 개체의 CWnd사용자 지정 할당을 수행하려면 이 메서드를 사용합니다. 이 설명에서는 왜 C++ Windows 개체를 삭제하는 데 CWnd::DestroyWindow을 사용해야 하며, delete 연산자를 대신 사용하지 말아야 하는지를 설명합니다.

지침을 따르면 정리 문제가 거의 발생하지 않습니다. 이러한 문제는 C++ 메모리를 삭제/해제하는 것을 잊거나, s와 같은 HWND시스템 리소스를 해제하지 않거나, 개체를 너무 많이 해제하는 등의 문제로 인해 발생할 수 있습니다.

문제

각 windows 객체(파생 클래스 CWnd의 객체)는 C++ 객체와 HWND 객체를 나타냅니다. C++ 개체는 애플리케이션의 힙에 할당되며 HWND창 관리자가 시스템 리소스에 할당합니다. 창 개체를 삭제하는 방법에는 여러 가지가 있으므로 시스템 리소스 또는 메모리 누수 방지 규칙 집합을 제공해야 합니다. 또한 이러한 규칙은 개체와 Windows 핸들이 두 번 이상 제거되지 않도록 해야 합니다.

창문을 부수기

다음은 Windows 개체를 삭제하는 두 가지 허용된 방법입니다.

  • 호출 CWnd::DestroyWindow 또는 Windows API DestroyWindow.

  • 연산자를 사용하여 명시적으로 삭제합니다 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 소멸자가 DestroyWindowm_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_hWndNULL로 될 것입니다. 자동 정리 개체를 호출 DestroyWindow 하면 C++ 개체가 사라집니다. 이 개체는 자동 정리 구현 PostNcDestroy에서 C++ delete 연산자에 의해 해제됩니다.

참고하십시오

숫자별 기술 노트
범주별 기술 정보