c++ - 在发布版本中删除类指针会导致内存问题

标签 c++ mfc clr

使用 VS2010 编写的/clr 的 MFC 应用程序。多线程 DLL (/MD) 运行时库。当我将 NDEBUG 的预处理器定义切换为 _DEBUG 时出现问题。 NDEBUG 禁用定义 _DEBUG 时弹出的断言。我在管理类指针的创建和删除时做错了什么吗?

从 NDEBUG 切换到 _DEBUG 后,我在运行时收到“_Block_Type_Is_Valid (pHead->nBlockUse)”断言失败错误。

A 类:“A.h”

#include "B.h"

class A
{
public:
    A(void);
    ~A(void);

    A(const A&);
    A& operator=(const A&);

    B* p_B;

};

A 类:“A.cpp”

#include "StdAfx.h"
#include "A.h"

A::A(void)
{
    p_B = new B();
}

A::~A(void)
{
    delete p_B;
}

// 1. copy constructor
A::A(const A& that)
{
     p_B = new B(); 
    *p_B = *that.p_B;
}

// 2. copy assignment operator
A& A::operator=(const A& that)
{
    *p_B = *that.p_B;
    return *this;
}

B 类:“B.h”

class B
{
public:
    B(void);
    ~B(void);

    B(const B&);
    B& operator=(const B&);
};

B 类:“B.cpp”

#include "StdAfx.h"
#include "B.h"

B::B(void) { }
B::~B(void) { }

// 1. copy constructor
B::B(const B& that)
{
}

// 2. copy assignment operator
B& B::operator=(const B& that)
{
    return *this;
}

ModalDlg.cpp(实例化A类对象的地方)

BOOL CTestingReleaseBuildDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    A a;

    // Set the icon for this dialog.  The framework does this automatically
    //  when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE);         // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon

    // TODO: Add extra initialization here

    return TRUE;  // return TRUE  unless you set the focus to a control
}

然后我只是在我的 MFC 对话框中实例化 A 类,这导致断言失败。我的问题是,“我在创建和删除类指针时做错了什么吗?”断言在类 A 的析构函数的“delete p_B”指令中特别失败。

编辑: 我用 BOOL CMyMFCClassDLG::OnInitDialog() { ... A a; 实例化 A 类...

编辑2: 我为 A 类和 B 类定义了复制构造函数和复制赋值运算符。他们永远不会被调用。

EDIT3:值得一提的是,如果我删除 A 的析构函数中的 delete p_B; 语句,则不会再出现断言失败。

EDIT4:程序在定义了/MDd 和 _DEBUG 的 Debug模式下运行良好。当我使用/MD 和 _DEBUG 在 Release模式下运行时断言失败。我认为这可能是导致问题的原因,因为/MD 可能应该与 NDEBUG 一起运行。

EDIT5:我按照@Christophe 的建议更新了代码,并插入了 A 类对象实例化位置的函数。我不想复制/粘贴模态对话框应用程序的其余部分,但您可以通过在 VS2010 中启动一个新的基于模态对话框的 MFC 应用程序并更改项目配置以使用/CLR 模式来复制确切的代码,设置运行时库到/MD 并在预处理器定义字段中包含 _DEBUG 关键字。

EDIT6:项目链接https://drive.google.com/drive/folders/1q0n9c6yMZ2ZKnakH6Z5NbVeGsAWfUAc1?usp=sharing

最佳答案

如果没有复制构造函数和赋值运算符,p_B 会从其原始 A 对象中克隆。所以被销毁的两个对象中的第一个将删除p_B,第二个对象将尝试删除已经删除的指针,即UB。

在您的编辑中,您已经定义了缺失的元素。您的复制构造函数的问题是它什么都不做。所以不幸的是,复制对象的 p_B 指针可能无效。你需要完成那些成员函数:

// 1. copy constructor
A::A(const A& that)
{
    p_B = new B(); 
    *p_B = *that->p_B;
}

对于拷贝构造函数,假设你保证 p_B 总是指向一个有效的 B 对象,并且假设没有切片的风险:

// 2. copy assignment operator
A& A::operator=(const A& that)
{
    *p_B = *that.p_B;        
    return *this;
}

如果您认为您不需要复制构造函数或赋值运算符,为了确保遵守规则 3,您也可以将它们声明为已删除:

A(const A&) = delete;
A& operator=(const A&) = delete;

如果您的代码不小心使用了它们,编译器会提示而不是生成代码和上述问题。

最后,您在初始化函数中实例化 A。但是对于你的非常短的片段,它似乎是这个函数的本地对象。因此,一旦您离开该功能,它就会被销毁。

关于c++ - 在发布版本中删除类指针会导致内存问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48285956/

相关文章:

用于在 XML 中存储设置的 C++ 库

c++ - 如何在模板类的 'namespace' 中创建非模板类型定义?

c++ - 关于C++ GUI项目类型和控件的问题

c++ - 如何强制 AfxMessageBox 以大型机为中心,而不是当前具有焦点的任何子窗口

c# - 关于 CLR 的 native 调用堆栈到底是什么?

c# - 哪个是 MSCorEE.h 在单声道编译器中的等效头文件?

c++ - 在 C++ 中重载自定义排序比较函数

c++ - 双图插入问题

c++ - 如何从以管理员模式运行的 MFC 应用程序创建没有管理员权限的新进程?

.net - .NET 4.5会引入CLR的新版本吗?