大家好,今天小編帶大家了解重載deletec操作符中的隱患。重載delete卻有隱患,到底是怎么一回事呢?讓我們一起來(lái)看看吧。
出于一些特殊的業(yè)務(wù)需要(比如統(tǒng)計(jì)程序的內(nèi)存使用狀況),我們可能會(huì)對(duì)new和delete操作符進(jìn)行重載。如果此時(shí)在工程中使用了外部鏈接庫(kù),并且在使用外部類時(shí)包含頭文件不夠嚴(yán)謹(jǐn),將會(huì)導(dǎo)致析構(gòu)階段出現(xiàn)外部類的析構(gòu)函數(shù)無(wú)法被正確執(zhí)行的情況。
我們做以下實(shí)驗(yàn)(開(kāi)發(fā)環(huán)境vs2017)
鏈接庫(kù)中定義的類:
頭文件mylib.h
#pragma once
class MyLib
{
public:
int* m_p;
MyLib();
~MyLib();
};
cpp文件mylib.cpp
注意我們?cè)谖鰳?gòu)函數(shù)中加了一條打印,來(lái)輔助判斷是否正確執(zhí)行了析構(gòu)
#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,包含了一個(gè)外部類指針,但在類定義中只做聲明沒(méi)有使用
#pragma once
class MyLib;
class LocalTest
{
public:
MyLib* m_lib;
LocalTest();
~LocalTest();
};
LocalTest類的構(gòu)造和析構(gòu)函數(shù)在test.cpp中
注意這里我們沒(méi)有包含外部類的頭文件mylib.h
#include "test.h"
LocalTest::LocalTest()
{
m_lib = nullptr;
}
LocalTest::~LocalTest()
{
if (m_lib)
{
delete m_lib;
m_lib = nullptr;
}
}
在另一個(gè)cpp文件中創(chuàng)建一個(gè)LocalTest對(duì)象,并給MyLib指針賦值,最后析構(gòu)LocalTest對(duì)象
#include <iostream>
#include "mylib.h"
#include "test.h"
//重載delete運(yùn)算符
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;
}
我們看一下運(yùn)行結(jié)果

可以看到外部類的析構(gòu)函數(shù)并沒(méi)有被執(zhí)行
我們反匯編證實(shí)一下


編譯器在執(zhí)行MyLib析構(gòu)時(shí)執(zhí)行的時(shí)我們重載的delete而非~MyLib()
現(xiàn)在我們做一點(diǎn)修改,在本地類test.cpp文件中包含外部類的頭文件,重新編譯運(yùn)行


可以看到外部類的析構(gòu)函數(shù)被正確執(zhí)行了。
再次查看匯編代碼,可以發(fā)現(xiàn)此時(shí)編譯器已經(jīng)找到了正確的析構(gòu)函數(shù)

而如果你將本地類的析構(gòu)函數(shù)的實(shí)現(xiàn)放在了頭文件中而非cpp中,幸運(yùn)的是這樣編譯器也能找到正確的找到析構(gòu)函數(shù)(~ ̄ ̄)~。
這就是重載delete時(shí)的隱患了,不知道大家有什么想法呢?歡迎在屏幕下方留言哦