C++重载delete的隐患

大家好,今天小编带大家了解重载deletec操作符中的隐患。重载delete却有隐患,到底是怎么一回事呢?让我们一起来看看吧。
出于一些特殊的业务需要(比如统计程序的内存使用状况),我们可能会对new和delete操作符进行重载。如果此时在工程中使用了外部链接库,并且在使用外部类时包含头文件不够严谨,将会导致析构阶段出现外部类的析构函数无法被正确执行的情况。
我们做以下实验(开发环境vs2017)
链接库中定义的类:
头文件mylib.h

#pragma once
class MyLib
{
public:
    int* m_p;
    MyLib();
    ~MyLib();
};

cpp文件mylib.cpp
注意我们在析构函数中加了一条打印,来辅助判断是否正确执行了析构

#include 
#include "mylib.h"
MyLib::MyLib()
{
    m_p = new int;
    *m_p = 1;
}

MyLib::~MyLib()
{
    std::cout << "MyLib Destructor" << std::endl;
    if (m_p)
    {
        delete m_p;
        m_p = nullptr;
    }
}

本地工程中的类test.h,包含了一个外部类指针,但在类定义中只做声明没有使用

#pragma once
class MyLib;
class LocalTest
{
public:
    MyLib* m_lib;
    LocalTest();
    ~LocalTest();
};

LocalTest类的构造和析构函数在test.cpp中
注意这里我们没有包含外部类的头文件mylib.h

#include "test.h"

LocalTest::LocalTest()
{
    m_lib = nullptr;
}

LocalTest::~LocalTest()
{
    if (m_lib)
    {
        delete m_lib;
        m_lib = nullptr;
    }
}

在另一个cpp文件中创建一个LocalTest对象,并给MyLib指针赋值,最后析构LocalTest对象

#include 
#include "mylib.h"
#include "test.h"

//重载delete运算符
void operator delete(void* p)
{
    //do something...
    free(p);
}

int main()
{
    LocalTest* test = new LocalTest;
    test->m_lib = new MyLib;//在这里给MyLib指针赋值
    delete test;
    system("pause");
    return 0;
}

我们看一下运行结果


image.png

可以看到外部类的析构函数并没有被执行
我们反汇编证实一下

image.png
image.png

编译器在执行MyLib析构时执行的时我们重载的delete而非~MyLib()
现在我们做一点修改,在本地类test.cpp文件中包含外部类的头文件,重新编译运行
image.png

image.png

可以看到外部类的析构函数被正确执行了。
再次查看汇编代码,可以发现此时编译器已经找到了正确的析构函数


image.png

而如果你将本地类的析构函数的实现放在了头文件中而非cpp中,幸运的是这样编译器也能找到正确的找到析构函数(~ ̄ ̄)~。
这就是重载delete时的隐患了,不知道大家有什么想法呢?欢迎在屏幕下方留言哦

你可能感兴趣的:(C++重载delete的隐患)