大家好,今天小编带大家了解重载deletec操作符中的隐患。重载delete却有隐患,到底是怎么一回事呢?让我们一起来看看吧。
出于一些特殊的业务需要(比如统计程序的内存使用状况),我们可能会对new和delete操作符进行重载。如果此时在工程中使用了外部链接库,并且在使用外部类时包含头文件不够严谨,将会导致析构阶段出现外部类的析构函数无法被正确执行的情况。
我们做以下实验(开发环境vs2017)
链接库中定义的类:
头文件mylib.h
#pragma once
class MyLib
{
public:
int* m_p;
MyLib();
~MyLib();
};
cpp文件mylib.cpp
注意我们在析构函数中加了一条打印,来辅助判断是否正确执行了析构
#include <iostream>
#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 <iostream>
#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;
}
我们看一下运行结果
![](https://img.haomeiwen.com/i11132565/017b3abcc0afb008.png)
可以看到外部类的析构函数并没有被执行
我们反汇编证实一下
![](https://img.haomeiwen.com/i11132565/dc593abe3869efc9.png)
![](https://img.haomeiwen.com/i11132565/93ff1d125ffa32e7.png)
编译器在执行MyLib析构时执行的时我们重载的delete而非~MyLib()
现在我们做一点修改,在本地类test.cpp文件中包含外部类的头文件,重新编译运行
![](https://img.haomeiwen.com/i11132565/c8b94b852a1dd8dd.png)
![](https://img.haomeiwen.com/i11132565/1c763f746a37b874.png)
可以看到外部类的析构函数被正确执行了。
再次查看汇编代码,可以发现此时编译器已经找到了正确的析构函数
![](https://img.haomeiwen.com/i11132565/18002fef06dd66eb.png)
而如果你将本地类的析构函数的实现放在了头文件中而非cpp中,幸运的是这样编译器也能找到正确的找到析构函数(~ ̄ ̄)~。
这就是重载delete时的隐患了,不知道大家有什么想法呢?欢迎在屏幕下方留言哦
网友评论