shared_ptr的問題
#include <iostream>
#include <string>
#include <memory>
using namespace std;
class Girl;
class Boy{
public:
Boy(){
cout << "Boy 構(gòu)造函數(shù)" << endl;
}
~Boy(){
cout << "~Boy 析構(gòu)函數(shù)" <<endl;
}
void setGirlFriend(shared_ptr<Girl> _girlFriend){
this->girlFriend = _girlFriend;
}
private:
shared_ptr<Girl> girlFriend;
};
class Girl{
public:
Girl(){
cout << "Girl 構(gòu)造函數(shù)" <<endl;
}
~Girl(){
cout << "~Girl 構(gòu)造函數(shù)" <<endl;
}
void setBoyFriend(shared_ptr<Boy> _boyFriend){
this->boyFriend = _boyFriend;
}
private:
shared_ptr<Boy> boyFriend;
};
void useTrap(){
shared_ptr<Boy> spBoy(new Boy());
shared_ptr<Girl> spGirl(new Girl());
//陷阱用法
spBoy->setGirlFriend(spGirl);
spGirl->setBoyFriend(spBoy);
}
int main(void){
useTrap();
return 0;
}
最后的運(yùn)行情況:
root@maokx:~/learn/smartPoint# g++ -std=c++11 -g test6.cpp -o test6
root@maokx:~/learn/smartPoint# ./test6
Boy 構(gòu)造函數(shù)
Girl 構(gòu)造函數(shù)
root@maokx:~/learn/smartPoint#
發(fā)現(xiàn)沒有調(diào)用析構(gòu)函數(shù),為什么呢?
useTrap函數(shù)結(jié)束后,函數(shù)中定義的智能指針被清掉,boy和girl指針的引用計(jì)數(shù)減1,還剩下1,對(duì)象中的智能指針還是托管他們的,所以函數(shù)結(jié)束后沒有將boy和gilr指針釋放的原因就是于此。
當(dāng)我們執(zhí)行useTrap函數(shù)時(shí),注意,是沒有結(jié)束此函數(shù),boy和girl指針其實(shí)是被兩個(gè)智能指針托管的,所以他們的引用計(jì)數(shù)是2:

從圖中可知:
無法釋放的原因是:循環(huán)引用
這種情況,很像類的頭文件的循環(huán)引用,釋放spBoy,必須謝謝spGirl,釋放spGirl的話,必須釋放spBoy,這就是死循環(huán)的情況,所以這種不行。
weak_ptr指針
weak_ptr 設(shè)計(jì)的目的是為配合 shared_ptr 而引入的一種智能指針來協(xié)助 shared_ptr 工作, 它只可以從一個(gè) shared_ptr 或另一個(gè) weak_ptr 對(duì)象構(gòu)造, 它的構(gòu)造和析構(gòu)不會(huì)引起引用記數(shù)的增加或減少。 同時(shí)weak_ptr 沒有重載*和->但可以使用 lock 獲得一個(gè)可用的 shared_ptr 對(duì)象。
弱指針的使用:
weak_ptr wpGirl_1; // 定義空的弱指針
weak_ptr wpGirl_2(spGirl); // 使用共享指針構(gòu)造
wpGirl_1 = spGirl; // 允許共享指針賦值給弱指針
弱指針也可以獲得引用計(jì)數(shù);
wpGirl_1.use_count()
弱指針不支持 * 和 -> 對(duì)指針的訪問;
#include <iostream>
#include <string>
#include <memory>
using namespace std;
class Girl;
class Boy{
public:
Boy(){
cout << "Boy 構(gòu)造函數(shù)" <<endl;
}
~Boy(){
cout << "~Boy 析構(gòu)函數(shù)" <<endl;
}
void setGirlFriend(shared_ptr<Girl> _girlFriend){
this->girlFriend = _girlFriend;
//在必要使用可以轉(zhuǎn)換成共享指針
shared_ptr<Girl> sp_girl;
sp_girl = this->girlFriend.lock();
cout << sp_girl.use_count() <<endl;
//使用完之后,再將共享指針NULL即可
sp_girl = NULL;
}
private:
weak_ptr<Girl> girlFriend;
};
class Girl{
public:
Girl(){
cout << "Girl 構(gòu)造函數(shù)" <<endl;
}
~Girl(){
cout << "~Girl 析構(gòu)函數(shù)" << endl;
}
void setBoyFriend(shared_ptr<Boy> _boyFriend){
this->boyFriend = _boyFriend;
}
private:
shared_ptr<Boy> boyFriend;
};
void useTrap(){
shared_ptr<Boy> spBoy(new Boy());
shared_ptr<Girl> spGirl(new Girl());
spBoy->setGirlFriend(spGirl);
spGirl->setBoyFriend(spBoy);
}
int main(void){
useTrap();
return 0;
}
運(yùn)行情況:
root@maokx:~/learn/smartPoint# g++ -std=c++11 -g test7.cpp -o test7
root@maokx:~/learn/smartPoint# ./test7
Boy 構(gòu)造函數(shù)
Girl 構(gòu)造函數(shù)
3
~Girl 析構(gòu)函數(shù)
~Boy 析構(gòu)函數(shù)
root@maokx:~/learn/smartPoint#
這樣就調(diào)用了析構(gòu)函數(shù),弱關(guān)聯(lián),就打破了相互引用的情況。
在類中使用弱指針接管共享指針,在需要使用時(shí)就轉(zhuǎn)換成共享指針去使用即可!
注意的事項(xiàng)
不要把一個(gè)原生指針給多個(gè)智能指針管理;
int *x = new int(10);
unique_ptr< int > up1(x);
unique_ptr< int > up2(x);
// 警告! 以上代碼使up1 up2指向同一個(gè)內(nèi)存,非常危險(xiǎn)
或以下形式:
up1.reset(x);
up2.reset(x);
這樣可以,引起重復(fù)釋放的問題,類似兩次delete
記得使用u.release()的返回值;
在調(diào)用u.release()時(shí)是不會(huì)釋放u所指的內(nèi)存的,這時(shí)返回值就是對(duì)這塊內(nèi)存的唯一索引,如果沒有使用這個(gè)返回值釋放內(nèi)存或是保存起來,這塊內(nèi)存就泄漏了.
這個(gè)名字很容易讓人誤解
禁止delete 智能指針get 函數(shù)返回的指針;
如果我們主動(dòng)釋放掉get 函數(shù)獲得的指針,那么智能 指針內(nèi)部的指針就變成野指針了,析構(gòu)時(shí)造成重復(fù)釋放,帶來嚴(yán)重后果!
禁止用任何類型智能指針get 函數(shù)返回的指針去初始化另外一個(gè)智能指針!
shared_ptr< int > sp1(new int(10));
// 一個(gè)典型的錯(cuò)誤用法 shared_ptr< int > sp4(sp1.get());
既然已經(jīng)托管指針了,那么,自己不要去管理了或者亂用了,就依靠托管的管理就可以了
最后的總結(jié)
智能指針雖然使用起來很方便,但是要注意使用智能指針的一些陷阱,否則會(huì)造成嚴(yán)重的內(nèi)存報(bào)錯(cuò)或者內(nèi)存泄露等問題!