C++11中的智能指針和垃圾回收使用
在C/C++中,我們需要自己管理動(dòng)態(tài)內(nèi)存區(qū),我們?cè)趯?xiě)代碼中可能會(huì)出現(xiàn)如下3中內(nèi)存管理的缺陷
- 野指針:內(nèi)存單元已經(jīng)釋放,但是指向它的指針還在使用
- 重復(fù)釋放:試圖是釋放已經(jīng)釋放過(guò)的內(nèi)存單元
- 內(nèi)存泄漏:不再使用的內(nèi)存單元沒(méi)有進(jìn)行釋放
C++惡心的地方就在于它存在指針,需要編寫(xiě)者自己管理內(nèi)存,所以內(nèi)存上面的問(wèn)題就會(huì)有很多,但是在其他語(yǔ)言,例如python,java,C#,他都不存在指針概念,也就意味著你不需要開(kāi)辟釋放內(nèi)存這些操作。而正因?yàn)镃++將指針暴露出來(lái),甚至將右值引用暴露出來(lái),才使得C++的運(yùn)行效率非常快。
為了減少C++中的內(nèi)存問(wèn)題,就出現(xiàn)了智能指針,它是一種對(duì)C風(fēng)格指針的優(yōu)化,它把內(nèi)存的釋放放在了智能指針的析構(gòu)函數(shù)中,這樣子就能減少一部分自己手動(dòng)釋放內(nèi)存的代碼。
1.C++11中的unique_ptr
#include<memory>
#include<iostream>
using namespace std;
int main()
{
? ? unique_ptr<int> up1(new int(11));
? ? unique_ptr<int> up2=up1;//無(wú)法通過(guò)編譯
? ? cout<<*up1<<endl;//11
? ? unique_ptr<int> up3=move(up1);//現(xiàn)在up3是數(shù)據(jù)的唯一指針
? ? cout<<*up3<<endl;//11
? ? cout<<*up1<<endl;//運(yùn)行錯(cuò)誤
? ? up3.reset();//釋放內(nèi)存
? ? up1.reset();//不會(huì)重復(fù)釋放內(nèi)存
? ? cout<<*up3<<endl;//運(yùn)行錯(cuò)誤
}我們知道unique_ptr正如它的名字一樣,它表示一個(gè)對(duì)象只能由一個(gè)指針綁定,不允許一個(gè)對(duì)象同時(shí)又多個(gè)unique_ptr綁定。
而且 unique_ptr只存在移動(dòng)語(yǔ)義,而不存在拷貝語(yǔ)義 ,我們看上面代碼中unique_ptr<int> up3=move(up1);,在unique_ptr中只存在移動(dòng)構(gòu)造函數(shù)和移動(dòng)賦值函數(shù),不存在拷貝構(gòu)造函數(shù)和拷貝賦值函數(shù)。所以說(shuō)我們只能用右值來(lái)構(gòu)造或賦值unique_ptr。
還有一種初始化unique_ptr的方法就是:make_unique<>(),相較于使用new初始化,前者內(nèi)存碎片化更少,在現(xiàn)代C++種主要使用,make_unique。
實(shí)際上,C++98中的auto_ptr和C++11中的unique_ptr實(shí)現(xiàn)的是同一個(gè)東西,但是在C++98中我們不存在移動(dòng)語(yǔ)義,所以auto_ptr它是存在拷貝構(gòu)造函數(shù)和拷貝賦值函數(shù)的,所以諸如:
auto_ptr<int> up2=up1;是可以通過(guò)編譯的,在C++11中我們廢棄掉了,auto_ptr也是這個(gè)原因。
2.C++11中的shared_ptr和weak_ptr
shared_ptr是一種共享式的指針,它采用引用計(jì)數(shù)的方式,來(lái)決定何時(shí)釋放內(nèi)存,引用計(jì)數(shù)就是說(shuō),它統(tǒng)計(jì)每個(gè)對(duì)象有幾個(gè)指針指向它。一旦一個(gè)對(duì)象的引用計(jì)數(shù)為0,即不存在指向它的指針,那么就釋放它。
weak_ptr是用來(lái)驗(yàn)證shared_ptr指向的內(nèi)存單元的有效性的,被它指向的對(duì)象的引用計(jì)數(shù)不會(huì)增加。
#include<memory>
#include<iostream>
using namespace std;
void Check(weak_ptr<int>& wp)
{
? ? shared_ptr<int> sp=wp.lock();
? ? if(sp!=nullptr)
? ? ? ? cout<<"still "<<*sp<<endl;
? ? else
? ? ? ? cout<<"pointer is invalid."<<endl;
}
int main()
{
? ? shared_ptr<int> sp1=make_shared<int>(22);
? ? shared_ptr<int> sp2=sp1;
? ? weak_ptr<int> wp=sp1;
? ? cout<<*sp1<<endl;
? ? cout<<*sp2<<endl;
? ? Check(wp);
? ? sp1.reset();
? ? cout<<*sp2<<endl;
? ? Check(wp);
? ? sp2.reset();
? ? Check(wp);
}22
22
still 22
22
still 22
pointer is invalid.
3.垃圾回收
雖然智能指針能夠幫助用戶有效管理堆內(nèi)存,但是它還是需要顯式聲明智能指針,而完全不需要指針的內(nèi)存管理方法也會(huì)更討人喜歡。這種方法就是垃圾回收機(jī)制,寫(xiě)代碼的時(shí)候不需要開(kāi)辟釋放內(nèi)存操作,這些操作都由編譯器自動(dòng)實(shí)現(xiàn),這種智能化的方案就是垃圾回收機(jī)制。
遺憾的是,C++不支持垃圾回收機(jī)制。
垃圾回收的方式有4種
基于引用計(jì)數(shù)的方法
其實(shí)就是和shared_ptr一樣的方式,就是一旦對(duì)象的引用次數(shù)為0就釋放它,python就是使用的這種方案,不過(guò)這種方案不好,它效率比較低,一旦對(duì)象創(chuàng)建,或者有指針指向它,都要計(jì)算引用此時(shí),而且它不能解決"環(huán)形引用"問(wèn)題
標(biāo)記-清除
這種方法就是存在一個(gè)根對(duì)象,它管理所有對(duì)象,依次遍歷每個(gè)對(duì)象,給它們引用的區(qū)域打上標(biāo)記,然后遍歷完成后,把所有沒(méi)有標(biāo)記的區(qū)域釋放掉,這種方案的缺陷在于會(huì)存在大量的內(nèi)存碎片
標(biāo)記-整理
它是在標(biāo)記-清除方案的基礎(chǔ)上,標(biāo)記完后不再遍歷釋放垃圾了,而是所有被標(biāo)記的區(qū)域,向左靠齊,這樣就減少了內(nèi)存碎片
標(biāo)記-拷貝
它是將內(nèi)存空間分為兩塊:From和to,剛開(kāi)始就從From空間種分配內(nèi)存,一旦From內(nèi)存滿了,就把From空間中所有活對(duì)象,拷貝到to空間中,而且都是向左靠齊的,然后再將From和to的角色互換。
很遺憾C++11目前還沒(méi)有公開(kāi)支持過(guò)垃圾回收,不過(guò)有些庫(kù)和有限編譯器支持了部分垃圾回收的功能
int main()
{
? ? int *p=new int;
? ? p+=10;
? ? p-=10;
? ? *p=10;
}上面代碼中,一旦p指向了其他區(qū)域,如果你的編譯器支持垃圾回收,例如采用的引用計(jì)時(shí)方式,那么一旦p移到了其他地區(qū),這個(gè)開(kāi)辟的new int空間,就會(huì)被釋放,更危險(xiǎn)的是,這塊空間會(huì)被其他線程使用,這時(shí)候,p如果又指回了原來(lái)的地方,那么p就是一個(gè)野指針。
為了防止,new int這塊空間被垃圾回收器回收掉,我們的一種方案是:
int main()
{
int *p=new int;
declare_reachable(p);
p+=10;
p-=10;
*p=10;
}
這里的declare_reachable函數(shù)顯式的告訴垃圾回收器,你不要取釋放這塊空間
到此這篇關(guān)于C++11中的智能指針和垃圾回收使用的文章就介紹到這了,更多相關(guān)C++11 智能指針和垃圾回收內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)銀行模擬
這篇文章主要介紹了C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)銀行模擬的相關(guān)資料,通過(guò)此文希望大家能理解離散化的方法,希望能幫助到大家,需要的朋友可以參考下2017-08-08
C語(yǔ)言實(shí)現(xiàn)一個(gè)簡(jiǎn)單的掃雷游戲
掃雷是電腦上很經(jīng)典的游戲,特意去網(wǎng)上玩了一會(huì),幾次調(diào)試之后,發(fā)現(xiàn)這個(gè)比三子棋要復(fù)雜一些,尤其是空白展開(kāi)算法上和堵截玩家有的一拼,與實(shí)際游戲差別較大,不能使用光標(biāo),下面來(lái)詳解每一步分析2021-10-10
Reactor反應(yīng)器的實(shí)現(xiàn)方法詳解
本篇文章是對(duì)Reactor反應(yīng)器的實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
Opencv學(xué)習(xí)教程之漫水填充算法實(shí)例詳解
這篇文章主要給大家介紹了Opencv學(xué)習(xí)教程之漫水填充算法的相關(guān)資料,文中給出了詳細(xì)的示例代碼供大家參考學(xué)習(xí),對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面跟著小編一起來(lái)學(xué)習(xí)學(xué)習(xí)吧。2017-06-06
C++中vector類的一些簡(jiǎn)單實(shí)現(xiàn)
C++中的std::vector是一個(gè)動(dòng)態(tài)數(shù)組(也被稱為可變大小數(shù)組)的容器類,它是C++標(biāo)準(zhǔn)庫(kù)提供的其中一種容器類,提供了方便的操作和管理動(dòng)態(tài)數(shù)組的功能,本文就給大家介紹了C++中vector類的簡(jiǎn)單實(shí)現(xiàn)代碼,需要的朋友可以參考下2023-08-08
C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的推箱子小游戲
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的推箱子小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07
項(xiàng)目之C++如何實(shí)現(xiàn)數(shù)據(jù)庫(kù)連接池
這篇文章主要介紹了項(xiàng)目之C++如何實(shí)現(xiàn)數(shù)據(jù)庫(kù)連接池問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
標(biāo)準(zhǔn)CSV格式的介紹和分析以及解析算法實(shí)例詳解
這篇文章主要介紹了標(biāo)準(zhǔn)CSV格式的介紹和分析以及解析算法實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2016-12-12
C++ 動(dòng)態(tài)數(shù)組模版類Vector實(shí)例詳解
這篇文章主要為大家詳細(xì)介紹了C++動(dòng)態(tài)數(shù)組模版類Vector實(shí)例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-02-02

