智慧指標的釋放_看完這篇,別再說不會智慧指標了
技術標籤:智慧指標的釋放
C++智慧指標
一、智慧指標的作用
上一篇介紹了記憶體池的原理和實現,詳情請見記憶體池設計與實現;
記憶體池可以幫助我們有效的對記憶體進行管理,智慧指標可以很方便的管理指標,避免出現記憶體洩漏;
智慧指標的作用
智慧指標的作用:智慧指標可以幫助我們避免在申請空間後忘記釋放造成記憶體洩漏的問題;因為智慧指標本身是一個類(後面也會自己實現一下),當出了類的作用域的時候,類會呼叫解構函式進行釋放資源。所以智慧指標的作用原理就是在函式結束時自動釋放記憶體空間,不需要手動釋放記憶體空間。
二、智慧指標的原理
我們這裡的指標指標主要指的是shared_ptr
,這也是一種引用計數型智慧指標
智慧指標才會釋放資源;
案例一
#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
的編譯引數;
使用智慧指標初始化有幾種方式,new
和make_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後臺伺服器開發 轉載是一種動力 分享是一種美德