1. 程式人生 > 其它 >智慧指標的釋放_看完這篇,別再說不會智慧指標了

智慧指標的釋放_看完這篇,別再說不會智慧指標了

技術標籤:智慧指標的釋放

C++智慧指標


一、智慧指標的作用

上一篇介紹了記憶體池的原理和實現,詳情請見記憶體池設計與實現;

記憶體池可以幫助我們有效的對記憶體進行管理,智慧指標可以很方便的管理指標,避免出現記憶體洩漏;

智慧指標的作用

智慧指標的作用:智慧指標可以幫助我們避免在申請空間後忘記釋放造成記憶體洩漏的問題;因為智慧指標本身是一個類(後面也會自己實現一下),當出了類的作用域的時候,類會呼叫解構函式進行釋放資源。所以智慧指標的作用原理就是在函式結束時自動釋放記憶體空間,不需要手動釋放記憶體空間。


二、智慧指標的原理

我們這裡的指標指標主要指的是shared_ptr,這也是一種引用計數型智慧指標

,引用計數顧名思義就是在記憶體中記錄有多少個智慧指標被引用,新增一個引用計數加一,過期引用計數則減一,當引用計數為0的時候,

智慧指標才會釋放資源;

案例一

#include
#include

usingnamespacestd;

classA
{
public:
A()
{
cout<"AConstructor"<endl;
}
~A()
{
cout<"ADestruct"<endl;
}
};



intmain(){
shared_ptrp=make_shared();cout<"count:"<endl;return0;
}

結果:

[email protected]:~/C++/Net_C++/demo4#./test1
AConstructor
count:1
ADestruct

我們再增加一個傳參,看一下引用計數:

案例二

#include
#include

usingnamespacestd;

classA
{
public:
A()
{
cout<"AConstructor"<endl;
}
~A()
{
cout<"ADestruct"<endl;
}
};

voidfun(shared_ptrp){
cout<<"funcount:"<endl;
}intmain(){shared_ptrp=make_shared();cout<"count:"<endl;
fun(p);cout<"count:"<endl;return0;
}

結果:

[email protected]:~/C++/Net_C++/demo4#./test1
AConstructor
count:1
funcount:2
count:1
ADestruct

通過上面的兩個例子,我們驗證了最開始說的:智慧指標本身是一個類(後面也會自己實現一下),當出了類的作用域的時候,類會呼叫解構函式進行釋放資源;


三、智慧指標的使用

智慧指標的使用比較簡單,在我們程式中需要包含標頭檔案:

#include

注意:智慧指標是C++11 的標準,在編譯的時候需要加上 -std=c++11 的編譯引數;

使用智慧指標初始化有幾種方式,newmake_shared,這裡推薦使用make_shared,原因是:make_shared標準庫函式,是最安全的分配和使用動態記憶體的方法,此函式在動態記憶體中分配一個物件並初始化它,返回指向此物件的shared_ptr;標頭檔案和share_ptr相同。

簡單給個案例:

案例三

#include
#include

usingnamespacestd;

classA
{
public:
A(intcount)
{
_nCount=count;
}
~A(){}
voidPrint(){
cout<<"count:"<<_ncount>endl;
}private:int_nCount;
};intmain(){shared_ptrp=make_shared(10);
p->Print();return0;
}

編譯過程;

[email protected]:~/C++/Net_C++/demo4# g++ -std=c++11 test2.cpp -o test2
[email protected]:~/C++/Net_C++/demo4# ./test2
count:10

四、智慧指標使用注意項

我們先來看一段程式碼:

案例四

#include
#include

usingnamespacestd;

classB;

classA
{
public:
shared_ptr_pb;
};classB
{public:shared_ptr_pa;
};intmain(){shared_ptrpa=make_shared();shared_ptrpb=make_shared();cout<<"pacount:"<endl;cout<<"pbcount:"<endl;
pa->_pb=pb;
pb->_pa=pa;cout<<"pacount:"<endl;cout<<"pbcount:"<endl;return0;
}

結果;

[email protected]:~/C++/Net_C++/demo4# g++ -std=c++11 test3.cpp -o test3
[email protected]:~/C++/Net_C++/demo4# ./test3
pa count:1
pb count:1
pa count:2
pb count:2

會發現,最終的引用計數為2,那麼結束後,引用計數不為0,他們在堆上的空間不會被釋放,這就是常說的迴圈引用

當然,這不是無解的,我們可以另外一種只能指標,只不過這是種弱指標---weak_ptr,這種指標不會增加引用計數,配合shared_ptr,可謂是郎才女貌,皆大歡喜呀!

案例五

#include
#include

usingnamespacestd;

classB;

classA
{
public:
weak_ptr_pb;
};classB
{public:
weak_ptr_pa;
};intmain(){shared_ptrpa=make_shared();shared_ptrpb=make_shared();cout<<"pacount:"<endl;cout<<"pbcount:"<endl;
pa->_pb=pb;
pb->_pa=pa;cout<<"pacount:"<endl;cout<<"pbcount:"<endl;return0;
}

結果:

[email protected]:~/C++/Net_C++/demo4# g++ -std=c++11 test3.cpp -o test3
[email protected]:~/C++/Net_C++/demo4# ./test3
pa count:1
pb count:1
pa count:1
pb count:1

很清晰的發現,在最後互相引用的時候,引用計數器沒有加一,最後出作用域的時候就會呼叫解構函式,進行記憶體釋放;


五、智慧指標的實現

實現智慧指標,無論是在面試還是深刻理解智慧指標方面,對我們幫助都是非常大的,理解了上面的原理,我們動手實現一個智慧指標:

智慧指標實現程式碼

#include

usingnamespacestd;

template<classT>classSmartPoint
{
public:
//建構函式
SmartPoint(T*p=NULL)
{
_ptr=p;
if(p!=NULL)
{
_count=1;
}
else
{
_count=0;
}
}
//解構函式
~SmartPoint()
{
if(--_count==0)
{
delete_ptr;
}
}
//拷貝建構函式
SmartPoint(constSmartPoint&src)
{
if(this!=&src)
{
_ptr=src._ptr;
_count=src._count;
_count++;
}
}

//過載賦值操作符
SmartPoint&operator=(constSmartPoint&src)
{
if(_ptr==src._ptr)
{
return*this;
}
if(_ptr)
{
_count--;
if(_count==0)
{
delete_ptr;
}
}
_ptr=src._ptr;
_count=src._count;
_count++;
return*this;
}

//過載操作符
T*operator->()
{
if(_ptr)
return_ptr;
}

//過載操作符
T&operator*()
{
if(_ptr)
return*_ptr;
}

size_tuse_count()
{
return_count;
}
private:
T*_ptr;
size_t_count;

};

voidUse(SmartPoint<char>p){
intn=p.use_count();
}

intmain(){
SmartPoint<char>sp1(newchar);
Use(sp1);
SmartPoint<char>sp2(sp1);
SmartPoint<char>sp3;
sp3=sp1;
intn=sp1.use_count();
return0;
}

往期精彩文章推薦

  • 記憶體池設計與實現
  • 恭喜你!發現寶藏一份--技術文章彙總
  • C++11 計時器!真香
  • 我們需要懂得CMake檔案

想了解學習更多C++後臺伺服器方面的知識,請關注:微信公眾號:====**CPP後臺伺服器開發**====


掃碼CPP後臺伺服器開發 4b52d6e13d9d68c879a1ddf9af658f10.png 68761c97b0ad6846ceeea3f62713e0f5.png 6675277b261e08e2afb1ee216489fedd.png bdc024da332976dfc9f9349d2c8710e9.gif 81ca0601a1eee93c8609fab99489617d.gif 29f572c04d741da3a6b67cb26aed29ac.png轉載是一種動力 分享是一種美德