c++智能指針的超詳細(xì)講解_第1頁
c++智能指針的超詳細(xì)講解_第2頁
c++智能指針的超詳細(xì)講解_第3頁
c++智能指針的超詳細(xì)講解_第4頁
c++智能指針的超詳細(xì)講解_第5頁
已閱讀5頁,還剩3頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第c++智能指針的超詳細(xì)講解目錄1.什么是智能指針2.原始指針的問題3.unique_ptr4.shared_ptr5.shared_ptr使用需要注意的點5.1不能將一個原始指針初始化多個shared_ptr5.2.循環(huán)引用問題6.智能指針小結(jié)總結(jié)

1.什么是智能指針

從比較簡單的層面來看,智能指針是RAII(ResourceAcquisitionIsInitialization,資源獲取即初始化)機(jī)制對普通指針進(jìn)行的一層封裝。這樣使得智能指針的行為動作像一個指針,本質(zhì)上卻是一個對象,這樣可以方便管理一個對象的生命周期。

在c++中,智能指針一共定義了4種:

auto_ptr、unique_ptr、shared_ptr和weak_ptr。其中,auto_ptr在C++11已被摒棄,在C++17中已經(jīng)移除不可用。

2.原始指針的問題

原始指針的問題大家都懂,就是如果忘記刪除,或者刪除的情況沒有考慮清楚,容易造成懸掛指針(danglingpointer)或者說野指針(wildpointer)。

我們看個簡單的例子

objtype*p=newobjtype();

p-func();

deletep;

上面的代碼結(jié)構(gòu)是我們經(jīng)??吹降?。里面的問題主要有以下兩點:

1.代碼的最后,忘記執(zhí)行deletep的操作。

2.第一點其實還好,比較容易發(fā)現(xiàn)也比較容易解決。比較麻煩的是,如果func()中有異常,deletep語句執(zhí)行不到,這就很難辦。有的同學(xué)說可以在func中進(jìn)行刪除操作,理論上是可以這么做,實際操作起來,會非常麻煩也非常復(fù)雜。

此時,智能指針就可以方便我們控制指針對象的生命周期。在智能指針中,一個對象什么情況下被析構(gòu)或被刪除,是由指針本身決定的,并不需要用戶進(jìn)行手動管理,是不是瞬間覺得幸福感提升了一大截,有點幸福來得太突然的意思,終于不用我自己手動刪除指針了。

3.unique_ptr

unique_ptr是獨享被管理對象指針?biāo)袡?quán)(owership)的智能指針。unique_ptr對象封裝一個原始指針,并負(fù)責(zé)其生命周期。當(dāng)該對象被銷毀時,會在其析構(gòu)函數(shù)中刪除關(guān)聯(lián)的原始指針。

創(chuàng)建unique_ptr:

#includeiostream

#includestring

#includememory

usingnamespacestd;

voidf1(){

unique_ptrintp(newint(5));

cout*pendl;

}

上面的代碼就創(chuàng)建了一個unique_ptr。需要注意的是,unique_ptr沒有復(fù)制構(gòu)造函數(shù),不支持普通的拷貝和賦值操作。因為unique_ptr獨享被管理對象指針?biāo)袡?quán),當(dāng)p2,p3失去p的所有權(quán)時會釋放對應(yīng)資源,此時會執(zhí)行兩次deletep的操作。

voidf1(){

unique_ptrintp(newint(5));

cout*pendl;

unique_ptrintp2(p);

unique_ptrintp3=p;

}

對于p2,p3對應(yīng)的行,IDE會提示報錯

無法引用函數(shù)std::__1::unique_ptr_Tp,_Dp::unique_ptr(conststd::__1::unique_ptrint,std::__1::default_deleteint)[其中_Tp=int,_Dp=std::__1::default_deleteint](已隱式聲明)--它是已刪除的函數(shù)

unique_ptr雖然不支持普通的拷貝和賦值操作,但卻可以將所有權(quán)進(jìn)行轉(zhuǎn)移,使用std::move方法即可。

voidf1(){

unique_ptrintp(newint(5));

unique_ptrintp2=std::move(p);

//error,此時p指針為空:cout*pendl;

cout*p2endl;

unique最常見的使用場景,就是替代原始指針,為動態(tài)申請的資源提供異常安全保證。

objtype*p=newobjtype();

p-func();

deletep

前面我們分析了這部分代碼的問題,如果我們修改一下

unique_ptrobjtypep(newobjtype());

p-func();

deletep

此時我們只要unique_ptr創(chuàng)建成功,unique_ptr對應(yīng)的析構(gòu)函數(shù)都能保證被調(diào)用,從而保證申請的動態(tài)資源能被釋放掉。

4.shared_ptr

我們提到的智能指針,很大程度上就是指的shared_ptr,shared_ptr也在實際應(yīng)用中廣泛使用。它的原理是使用引用計數(shù)實現(xiàn)對同一塊內(nèi)存的多個引用。在最后一個引用被釋放時,指向的內(nèi)存才釋放,這也是和unique_ptr最大的區(qū)別。當(dāng)對象的所有權(quán)需要共享(share)時,share_ptr可以進(jìn)行賦值拷貝。

shared_ptr使用引用計數(shù),每一個shared_ptr的拷貝都指向相同的內(nèi)存。每使用他一次,內(nèi)部的引用計數(shù)加1,每析構(gòu)一次,內(nèi)部的引用計數(shù)減1,減為0時,刪除所指向的堆內(nèi)存。

std::shared_ptrintp4=newint(1)

上面這種寫法是錯誤的,因為右邊得到的是一個原始指針,前面我們講過shared_ptr本質(zhì)是一個對象,將一個指針賦值給一個對象是不行的。

voidf2(){

shared_ptrintp=make_sharedint

shared_ptrintp2(p);

shared_ptrintp3=p;

以上寫法都是可以的

voidf2(){

shared_ptrintp=make_sharedint

int*p2=p.get();

cout*p2endl;

上面的寫法,可以獲取shared_ptr的原始指針。

5.shared_ptr使用需要注意的點

5.1不能將一個原始指針初始化多個shared_ptr

voidf2(){

int*p0=newint(1);

shared_ptrintp1(p0);

shared_ptrintp2(p0);

cout*p1endl;

上面代碼就會報錯。原因也很簡單,因為p1,p2都要進(jìn)行析構(gòu)刪除,這樣會造成原始指針p0被刪除兩次,自然要報錯。

5.2.循環(huán)引用問題

shared_ptr最大的坑就是循環(huán)引用。引用網(wǎng)絡(luò)上的一個例子:

structFather

shared_ptrSonson_;

structSon

shared_ptrFatherfather_;

intmain()

autofather=make_sharedFather

autoson=make_sharedSon

father-son_=son;

son-father_=father;

return0;

}

該部分代碼會有內(nèi)存泄漏問題。原因是

1.main函數(shù)退出之前,F(xiàn)ather和Son對象的引用計數(shù)都是2。

2.son指針銷毀,這時Son對象的引用計數(shù)是1。

3.father指針銷毀,這時Father對象的引用計數(shù)是1。

4.由于Father對象和Son對象的引用計數(shù)都是1,這兩個對象都不會被銷毀,從而發(fā)生內(nèi)存泄露。

為避免循環(huán)引用導(dǎo)致的內(nèi)存泄露,就需要使用weak_ptr。weak_ptr并不擁有其指向的對象,也就是說,讓weak_ptr指向shared_ptr所指向?qū)ο螅瑢ο蟮囊糜嫈?shù)并不會增加。

使用weak_ptr就能解決前面提到的循環(huán)引用的問題,方法很簡單,只要讓Son或者Father包含的shared_ptr改成weak_ptr就可以了。

structFather

shared_ptrSonson_;

structSon

weak_ptrFatherfather_;

intmain()

autofather=make_sharedFather

autoson=make_sharedSon

father-son_=son;

son-father_=father;

return0;

}

1.main函數(shù)退出前,Son對象的引用計數(shù)是2,而Father的引用計數(shù)是1。

2.son指針銷毀,Son對象的引用計數(shù)變成1。

3.father指針銷毀,F(xiàn)ather對象的引用計數(shù)變成0,導(dǎo)致Father對象析構(gòu),F(xiàn)ather對象的析構(gòu)會導(dǎo)致它包含的son_指針被銷毀,這時Son對象的引用計數(shù)變成0,所以Son對象也會被析構(gòu)。

6.智能指針小結(jié)

我們該如何選擇智能指針:

如果程序要使用多個指向同一個對象的指針,應(yīng)選擇shared_ptr。這樣的情況包括

1.有一個指針數(shù)組,并使用一些輔助指針來標(biāo)示特定的元素,如最大的元素和最小的元素;

2.兩個對象包含都指向第三個對象的指針;

3.STL容器包含指針。很多STL算法都支持復(fù)制和賦值操作,這些操作可用于shared_ptr,但不能用于unique_ptr(編譯器發(fā)出warning)和auto_ptr(行為不確定)。如果你的編

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論