c++ - MFC CView(CFormView)破坏崩溃

标签 c++ mfc destructor

根据这个 stackoverflow 问题:

What is the correct way to programmatically quit an MFC application?

我正在使用 AfxGetMainWnd()->PostMessage(WM_CLOSE,0,0); 退出 MFC 程序。 (SDI,CFrameWnd 包含一个带有两个 CFormView 的 CSplitterWnd)

正如预期的那样,这会调用 DestroyWindow()

我面临的问题是,在派生的 CFormView 销毁之后,根据 MSDN:

After calling DestroyWindow on a non-auto-cleanup object, the C++ object will still be around, but m_hWnd will be NULL. [MSDN]

现在 CView 析构函数被调用,此时它执行

CDocument::RemoveView()...
CDocument::UpdateFrameCounts()

它在以下断言上失败:ASSERT(::IsWindow(pView->m_hWnd));

我检查过,m_hWnd 已经在之前调用的派生 CView 析构函数中设置为 NULL。

我做错了什么?

编辑:

这是一张图表,说明了为什么我要发送 WM_CLOSE 消息而不是 WM_QUIT。

enter image description here

我认为答案就在这个 MSDN Technical Note 中, 但我想不通。

编辑 2:

事物被调用的顺序:

1- AfxGetMainWnd()->PostMessage(WM_CLOSE,0,0);

2- 派生 CFrameWnd::OnClose()

3- CFrameWnd::OnClose()

调用 CWinApp::CloseAllDocuments(BOOL bEndSession);

调用 CDocManager::CloseAllDocuments(BOOL bEndSession)

调用 CDocTemplate::CloseAllDocuments(BOOL)

调用 CDocument::OnCloseDocument()

现在,在这个函数中

while (!m_viewList.IsEmpty())
{
    // get frame attached to the view
    CView* pView = (CView*)m_viewList.GetHead();
    ASSERT_VALID(pView);
    CFrameWnd* pFrame = pView->EnsureParentFrame();

    // and close it
    PreCloseFrame(pFrame);
    pFrame->DestroyWindow();
    // will destroy the view as well
}

所以我们看到 CWnd::DestroyWindow() 被调用了,所以:

4- 派生的 CFormView 析构函数

5- CScrollView::~CScrollView()

6- CView::~CView()

调用 CDocument::RemoveView(CView* pView)

调用 CDocument::OnChangedViewList()

调用 CDocument::UpdateFrameCounts()

这里崩溃了:ASSERT(::IsWindow(pView->m_hWnd));

因为 pView->m_hWndNULL...

编辑 3:

我想通了问题是什么:

第一个 View 的析构函数正在删除一个未初始化的指针,即 UB。这会使析构函数挂起并且永远不会完成。

通常,第二个 View 的析构函数仅在第一个 View 完成时调用。但在这种情况下,尽管第一个从未完成,但它仍在执行。

由于从未调用过第一个 View 基类析构函数,因此从未为第一个 View 调用过此函数:

void CDocument::RemoveView(CView* pView)
{
    ASSERT_VALID(pView);
    ASSERT(pView->m_pDocument == this); // must be attached to us

    m_viewList.RemoveAt(m_viewList.Find(pView));
    pView->m_pDocument = NULL;

    OnChangedViewList();    // must be the last thing done to the document
}

我们可以看到该 View 已从 m_viewList 中删除。

这意味着当第二个 View 析构函数完成时,在:

void CDocument::UpdateFrameCounts()
     // assumes 1 doc per frame
{
    // walk all frames of views (mark and sweep approach)
    POSITION pos = GetFirstViewPosition();
    while (pos != NULL)
    {
...

pos 应该是 NULL,但实际上不是。导致崩溃。

最佳答案

我认为您关闭框架的方式不是问题所在。 我的猜测是您手动销毁了其中一个 View ,而您应该让 MFC 删除它们(您可能对其中一个 View 调用了 DestroyWindow)

关于c++ - MFC CView(CFormView)破坏崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32661010/

相关文章:

java - 一行条件语句应该使用括号吗?

c++ - 如何确保从我的派生类调用纯虚方法?

c++ - 使用 MFC 以 Windows XP 为目标的 Visual Studio 2012 项目

c++ - gdb 可以中断隐式类方法吗?

c++ - 引用的临时对象的析构函数

c++ - "Assignable"到底是什么意思?

c++ - 替换 Wchar_t

c++ - MFC 编辑框 - 每次击键多个字符?

c++ - 在 C++ 中以 mm/dd/yyyy 获取当前时间

delphi - Delphi 对象上的 Destroy 方法和 Finalize 方法有什么区别?