C++如何用智能指針管理內(nèi)存資源
1.簡(jiǎn)介
C++作為一門應(yīng)用廣泛的高級(jí)編程語言,卻沒有像Java、C#等語言擁有垃圾回收(Garbage Collection )機(jī)制來自動(dòng)進(jìn)行內(nèi)存管理,這也是C++一直被詬病的一點(diǎn)。C++在發(fā)展的過程中,一直致力于解決內(nèi)存泄漏,C++雖然基于效率的考慮,沒有采用垃圾回收機(jī)制,但從C++98開始,推出了智能指針(Smart Pointer)來管理內(nèi)存資源,以彌補(bǔ)C++在內(nèi)存管理上的技術(shù)空白。
智能指針是C++程序員們一件管理內(nèi)存的利器,使用智能指針管理內(nèi)存資源,實(shí)際上就是將申請(qǐng)的內(nèi)存資源交由智能指針來管理,是RAII技術(shù)的一種實(shí)現(xiàn)。RAII是C++的之父Bjarne Stroustrup教授提出的概念,RAII全稱是“Resource Acquisition is Initialization”,直譯過來是“資源獲取即初始化”,也就是說在構(gòu)造函數(shù)中獲取資源,在析構(gòu)函數(shù)中釋放資源。因?yàn)镃++的語言機(jī)制保證了,當(dāng)一個(gè)對(duì)象創(chuàng)建的時(shí)候,自動(dòng)調(diào)用構(gòu)造函數(shù),當(dāng)對(duì)象超出作用域的時(shí)候會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù)。所以,在RAII的指導(dǎo)下,我們應(yīng)該使用類來管理資源,將資源和對(duì)象的生命周期綁定。
“資源獲取即初始化”,在使用智能指針管理內(nèi)存資源時(shí),“資源”指的是通過new或malloc申請(qǐng)的內(nèi)存資源,“初始化”指的是使用申請(qǐng)的內(nèi)存資源來初始化棧上的智能指針類對(duì)象。使用智能指針管理內(nèi)存資源的好處顯而易見,通過智能指針對(duì)象在聲明周期結(jié)束時(shí),自動(dòng)調(diào)用析構(gòu)函數(shù),在析構(gòu)函數(shù)中完成對(duì)內(nèi)存資源的釋放,即自動(dòng)的調(diào)用內(nèi)存資源的釋放代碼,避免因忘記對(duì)內(nèi)存資源的釋放導(dǎo)致內(nèi)存泄漏。
2.實(shí)例
下面看一個(gè)使用由C++11引入的智能指針unique_ptr來管理內(nèi)存資源的例子。
#include <memory> #include <iostream> using namespace std; class A { public: A() {} ~A() { cout<<"A's destructor"<<endl; } void Hello() { cout<<"use smart pointer to manage memory resources as far as possible"<<endl; } }; int main() { unique_ptr<A> pA(new A); pA->Hello(); return 0; }
程序輸出:
use smart pointer to manage memory resources as far as possible
A's destructor
可見在main()函數(shù)結(jié)束后,類A的析構(gòu)函數(shù)被自動(dòng)調(diào)用,完成了內(nèi)存資源了釋放。
在創(chuàng)建智能指針對(duì)象時(shí),也可以暫時(shí)不指定內(nèi)存資源,先創(chuàng)建一個(gè)空的智能指針對(duì)象??罩悄苤羔槍?duì)象不可以進(jìn)行任何操作,但可以使用 get() 成員函數(shù)來判斷是否存在內(nèi)存資源,如果為空則可以指定內(nèi)存資源。類似于如下操作:
unique_ptr<int> pInt; if (pInt.get()==nullptr) { pInt.reset(new int(8)); cout<<*pInt<<endl; }
使用 unique_ptr 智能指針來管理內(nèi)存資源時(shí),是對(duì)內(nèi)存資源的獨(dú)占式管理,即內(nèi)存資源的所有權(quán)不能進(jìn)行共享,同一時(shí)刻只能有一個(gè) unique_ptr 對(duì)象占有某個(gè)內(nèi)存資源。如果發(fā)生賦值或拷貝構(gòu)造,則會(huì)在編譯期報(bào)錯(cuò),因?yàn)閡nique_ptr禁止了拷貝語義,提高了代碼的安全性。
unique_ptr<int> pInt(new int(8)); unique_ptr<int> pInt1=pInt; //編譯報(bào)錯(cuò) unique_ptr<int> pInt2(pInt); //編譯報(bào)錯(cuò)
當(dāng)然,可以通過移動(dòng)語義完成內(nèi)存資源的所有權(quán)轉(zhuǎn)移,轉(zhuǎn)移之后,原智能指針對(duì)象變?yōu)榭罩悄苤羔槍?duì)象,不能再對(duì)內(nèi)存資源進(jìn)行任何操作,否則會(huì)發(fā)生運(yùn)行時(shí)錯(cuò)誤,但我們也可以使用get()成員函數(shù)進(jìn)行判空處理。
unique_ptr<int> pInt(new int(8)); unique_ptr<int> pInt1=std::move(pInt); //轉(zhuǎn)移所有權(quán) *pInt=6; //對(duì)空智能指針進(jìn)行賦值操作將報(bào)運(yùn)行時(shí)錯(cuò)誤 if(!pInt.get()) //判空處理更安全 { *pInt=6; }
獨(dú)占式的內(nèi)存資源管理可以使用 unique_ptr 來完成,但是如果想對(duì)內(nèi)存資源進(jìn)行共享式管理,那么 unique_ptr 就無能為力了。shared_prt 使用引用計(jì)數(shù)來實(shí)現(xiàn)對(duì)內(nèi)存資源的共享式管理,當(dāng)對(duì)內(nèi)存資源的引用計(jì)數(shù)變?yōu)?時(shí),由最后一個(gè)對(duì)內(nèi)存資源擁有管理權(quán)的智能指針對(duì)象完成對(duì)內(nèi)存資源的釋放。
#include <memory> #include <iostream> using namespace std; class A { public: A() {} ~A() { cout << "A's destructor" << endl; } void Hello() { cout << "use smart pointer to manage memory resources as far as possible" << endl; } }; int main() { shared_ptr<A> spInt(new A); //接管內(nèi)存資源 cout << "reference count "<<spInt.use_count() << endl; shared_ptr<A> spInt1 = spInt; //spInt1獲取內(nèi)存資源的管理權(quán) spInt1->Hello(); cout << "reference count " << spInt.use_count() << endl; spInt1.reset(); //spInt1放棄對(duì)內(nèi)存資源的管理權(quán) cout << "reference count " << spInt.use_count() << endl; }
程序編譯運(yùn)行結(jié)果:
reference count 1
use smart pointer to manage memory resources as far as possible
reference count 2
reference count 1
A's destructor
3.智能指針使用注意事項(xiàng)
智能指針雖然增強(qiáng)了安全性,避免了潛在的內(nèi)存泄漏,但是我們?cè)谑褂脮r(shí)還是應(yīng)該遵守一定的規(guī)則,以保證代碼的健壯性。
(1)smart_ptr<T> 不等于 T*,使用時(shí)不能完全按照T*來使用。因?yàn)閟mart_ptr<T>本質(zhì)上是類對(duì)象,一個(gè)用于管理內(nèi)存資源的智能指針類對(duì)象,而T*是一個(gè)指向類型T的指針,二者不能隨意地轉(zhuǎn)換和賦值;
(2)使用獨(dú)立的語句將newed對(duì)象置入智能指針,因?yàn)槭褂门R時(shí)智能指針對(duì)象可能會(huì)引發(fā)內(nèi)存泄漏。比如下面的語句:
process(shared_ptr<A>(new A),foo());
實(shí)際上對(duì) process() 函數(shù)調(diào)用時(shí)編譯器需要完成如下三步為process()準(zhǔn)備好實(shí)參。
(1)調(diào)用函數(shù)foo();
(2)執(zhí)行new A表達(dá)式;
(3)調(diào)用shared_ptr<A>構(gòu)造函數(shù),初始化智能指針對(duì)象。
實(shí)際上,不同的編譯器在執(zhí)行上述三個(gè)語句時(shí)可能會(huì)有不同的順序,如果編譯器將(2.2)放在(2.1)之前執(zhí)行,執(zhí)行順序如下:
(1)執(zhí)行new A表達(dá)式;
(2)調(diào)用函數(shù)foo();
(3)調(diào)用shared_ptr<A>構(gòu)造函數(shù),初始化智能指針對(duì)象。
如果在調(diào)用函數(shù)foo()時(shí)拋出異常,那么new A表達(dá)式產(chǎn)生的指向堆對(duì)象指針將會(huì)丟失,于是產(chǎn)生了內(nèi)存泄漏。解決辦法就是使用獨(dú)立的語句將newed對(duì)象置入智能指針,做法如下:
shared_ptr<A> spA(new A); process(spA,foo());
以上就是C++如何用智能指針管理內(nèi)存資源的詳細(xì)內(nèi)容,更多關(guān)于c++ 智能指針管理內(nèi)存的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Matlab實(shí)現(xiàn)別踩白塊小游戲的示例代碼
別踩白塊是一款音樂類休閑游戲,游戲的玩法不難,只需跟著音樂的節(jié)奏點(diǎn)中對(duì)的方塊即可。本文將用Matlab實(shí)現(xiàn)這一經(jīng)典游戲,感興趣的可以了解一下2022-03-03C++ Invalidaterect()函數(shù)作用案例詳解
這篇文章主要介紹了C++ Invalidaterect()函數(shù)作用案例詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08VisualStudio Community2019在安裝的過程中無法進(jìn)入安裝界面的解決方法
這篇文章主要介紹了VisualStudio Community2019在安裝的過程中無法進(jìn)入安裝界面的解決方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03C++中const的實(shí)現(xiàn)機(jī)制深入分析
C語言以及C++語言中的const究竟表示什么?其具體的實(shí)現(xiàn)機(jī)制又是如何實(shí)現(xiàn)的呢?本文將對(duì)這兩個(gè)問題進(jìn)行一些分析,需要了解的朋友可以參考下2012-12-12Visual Studio 2019 如何新建 Win32項(xiàng)目的方法步驟
這篇文章主要介紹了Visual Studio 2019 如何新建 Win32項(xiàng)目的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03