C++面向?qū)ο缶幊讨鰳?gòu)詳解
1. 概述
類的析構(gòu)函數(shù)執(zhí)行與構(gòu)造函數(shù)相反的操作,當(dāng)對(duì)象結(jié)束其生命周期,程序就會(huì)自動(dòng)執(zhí)行析構(gòu)函數(shù):
class ImageEx
{
public:
ImageEx()
{
cout << "Execute the constructor!" << endl;
}
~ImageEx()
{
cout << "Execute the destructor!" << endl;
}
};
int main()
{
ImageEx imageEx;
return 0;
}
那么同樣的問題來了,為什么要有析構(gòu)函數(shù)呢?
2. 詳論
2.1. 對(duì)象生命周期
在經(jīng)典C++中,需要通過new/delete來手動(dòng)管理動(dòng)態(tài)內(nèi)存。如果我們?cè)陬愔猩暾?qǐng)一個(gè)動(dòng)態(tài)數(shù)組,并且通過自定義的函數(shù)Release()來釋放它:
class ImageEx
{
public:
ImageEx()
{
cout << "Execute the constructor!" << endl;
data = new unsigned char[10];
}
~ImageEx()
{
cout << "Execute the destructor!" << endl;
}
void Release()
{
delete[] data;
data = nullptr;
}
private:
unsigned char * data;
};
int main()
{
{
ImageEx imageEx;
imageEx.Release();
}
return 0;
}
那么,當(dāng)類對(duì)象離開作用域,結(jié)束生命周期之前,就必須顯示調(diào)用一次成員函數(shù)Release(),否則就會(huì)造成內(nèi)存泄漏:對(duì)象在調(diào)用析構(gòu)函數(shù)之后,只會(huì)銷毀數(shù)據(jù)成員data本身,而不是其指向的內(nèi)存。
那么,一個(gè)合理的實(shí)現(xiàn)是,將成員函數(shù)Release()放入到析構(gòu)函數(shù):
class ImageEx
{
public:
ImageEx()
{
cout << "Execute the constructor!" << endl;
data = new unsigned char[10];
}
~ImageEx()
{
Release();
cout << "Execute the destructor!" << endl;
}
private:
unsigned char * data;
void Release()
{
delete[] data;
data = nullptr;
}
};
int main()
{
{
ImageEx imageEx;
}
return 0;
}
這樣,當(dāng)類對(duì)象離開作用域,結(jié)束生命周期之前,就自動(dòng)通過析構(gòu)函數(shù),實(shí)現(xiàn)了動(dòng)態(tài)數(shù)組的釋放。好處是顯而易見的:實(shí)現(xiàn)了類似于內(nèi)置數(shù)據(jù)類型對(duì)象的生命周期管理,我們可以像使用內(nèi)置數(shù)據(jù)類型對(duì)象一樣使用類對(duì)象。
2.2. 不一定需要顯式析構(gòu)
在一些現(xiàn)代高級(jí)編程語言(C#、Java、Javascript)中,已經(jīng)不用去手動(dòng)管理動(dòng)態(tài)內(nèi)存,取而代之的,是其與操作系統(tǒng)的中間件(.net,jvm,瀏覽器)的GC(垃圾回收)機(jī)制。而在現(xiàn)代C++中,提倡通過智能指針(std::shared_ptr、std::unique_ptr、std::weak_ptr)來管理動(dòng)態(tài)內(nèi)存;對(duì)于動(dòng)態(tài)數(shù)組,則使用標(biāo)準(zhǔn)容器std::vector則更好。在兩者的內(nèi)部都實(shí)現(xiàn)了前文提到的對(duì)象生命周期管理,在離開作用域后,通過析構(gòu)函數(shù)自動(dòng)釋放管理的內(nèi)存,無需再手動(dòng)進(jìn)行回收。
那么,一個(gè)顯而易見的推論就出來了,如果我們?cè)陬愔惺褂弥悄苤羔樆蛘遶ector容器來替代new/delete管理動(dòng)態(tài)內(nèi)存,是不是就可以不用析構(gòu)函數(shù)了?嚴(yán)格來說,是不用顯式使用析構(gòu)函數(shù):
class ImageEx
{
public:
ImageEx():
data(10)
{
cout << "Execute the constructor!" << endl;
}
private:
std::vector<unsigned char> data;
};
int main()
{
ImageEx imageEx;
return 0;
}
實(shí)際上,并不是這個(gè)類不存在析構(gòu)函數(shù),而是編譯器會(huì)為它生成一個(gè)合成的析構(gòu)函數(shù),在這個(gè)析構(gòu)函數(shù)體中,什么也不用做。因?yàn)轭愔械膭?dòng)態(tài)內(nèi)存,已經(jīng)交由std::vector容器來管理。當(dāng)類對(duì)象離開作用域調(diào)用析構(gòu)函數(shù)之后,會(huì)銷毀這個(gè)std::vector容器數(shù)據(jù)成員,進(jìn)而觸發(fā)其析構(gòu)函數(shù),釋放其管理的內(nèi)存。
2.3. 析構(gòu)的必要性
根據(jù)上一節(jié)內(nèi)容,不一定需要顯式析構(gòu)。因?yàn)楝F(xiàn)代C++的一些機(jī)制能夠幫你自動(dòng)管理動(dòng)態(tài)內(nèi)存。但是析構(gòu)函數(shù)還是必要的,這是由于C++語言本身的性質(zhì)決定的。作為C語言大部分內(nèi)容的超集,需要兼容C語言手動(dòng)管理內(nèi)存的特性。更重要的是,現(xiàn)代操作系統(tǒng)幾乎全部由C語言編寫,與底層的交互不可避免的需要手動(dòng)使用動(dòng)態(tài)內(nèi)存管理。
3. 總結(jié)
所以我們就能理解了,C++這門語言的設(shè)計(jì)哲學(xué)就是就是這樣:既想要C語言的高性能,也想要高級(jí)語言高度抽象的特性。如果我們必須兼容C語言底層設(shè)計(jì),那我們最好使用析構(gòu)函數(shù)釋放動(dòng)態(tài)內(nèi)存;否則多數(shù)情況下,我們應(yīng)該使用智能指針或者stl容器來管理動(dòng)態(tài)內(nèi)存,從而避免顯示使用析構(gòu)函數(shù)。
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
C++定義和初始化string對(duì)象實(shí)例詳解
這篇文章主要為大家介紹了C++定義和初始化string對(duì)象實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
OpenCV邊緣提取算法流程的實(shí)現(xiàn)(附DEMO)
本文主要介紹了OpenCV邊緣提取算法流程的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08
C++ 中類對(duì)象類型的轉(zhuǎn)化的實(shí)例詳解
這篇文章主要介紹了C++ 中類對(duì)象類型的轉(zhuǎn)化的實(shí)例詳解的相關(guān)資料,這里提供實(shí)例幫助大家學(xué)習(xí)理解這部分內(nèi)容,需要的朋友可以參考下2017-08-08
Qt5實(shí)現(xiàn)文本編輯器(附詳細(xì)代碼)
QT是一個(gè)跨平臺(tái)的GUI開發(fā)框架,我使用的QT5 C++版本的,本文主要介紹了Qt5實(shí)現(xiàn)文本編輯器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07
FFmpeg實(shí)戰(zhàn)之分離出PCM數(shù)據(jù)
PCM(Pulse?Code?Modulation,脈沖編碼調(diào)制)音頻數(shù)據(jù)是未經(jīng)壓縮的音頻采樣數(shù)據(jù)裸流,它是由模擬信號(hào)經(jīng)過采樣、量化、編碼轉(zhuǎn)換成的標(biāo)準(zhǔn)數(shù)字音頻數(shù)據(jù)。本文將通過FFmpeg實(shí)現(xiàn)分離PCM數(shù)據(jù),感興趣的可以了解一下2023-02-02

