一起聊聊C++中的智能指針
一:背景
我們知道 C++ 是手工管理內(nèi)存的分配和釋放,對(duì)應(yīng)的操作符就是 new/delete
和 new[] / delete[]
, 這給了程序員極大的自由度也給了我們極高的門檻,弄不好就得內(nèi)存泄露,比如下面的代碼:
void test() { int* i = new int(10); *i = 10; } int main() { test(); }
這段代碼因?yàn)橛昧?new 而忘了 delete,導(dǎo)致在 nt heap
上分配的 i 隨著棧地址的回收而成了一塊孤懸海外的內(nèi)存占用,所以修正后的代碼如下:
void test() { int* i = new int(10); *i = 10; delete i; } int main() { test(); }
但這種寫法比較麻煩,智者千慮必有一失,總會(huì)有忘記加 delete 的時(shí)候,那怎么辦呢? 大家應(yīng)該知道內(nèi)存自動(dòng)管理有兩種手段。
1.引用計(jì)數(shù)
代表作有 Python,PHP,還有 windows 的句柄管理。
2.引用跟蹤
代表作有 C#,JAVA 等一眾工程化語言。
因?yàn)?nbsp;引用計(jì)數(shù) 實(shí)現(xiàn)比較簡單,主要就是記錄下對(duì)象的引用次數(shù),次數(shù)為 0 則釋放,所以可完全借助 類的構(gòu)造函數(shù)析構(gòu)函數(shù) 和 棧的自動(dòng)回收特性 弄一個(gè)簡單的 引用計(jì)數(shù) ,對(duì)應(yīng)著如下四個(gè)關(guān)鍵詞。
- auto_ptr
- shared_ptr
- unique_ptr
- weak_ptr
接下來我們逐個(gè)聊一聊。
二:關(guān)鍵詞解析
1. auto_ptr
這是 C++ 最早出現(xiàn)一個(gè)的 簡單引用計(jì)數(shù)法,參考代碼如下:
void test() { auto_ptr<int> ptr = auto_ptr<int>(new int(10)); } int main() { test(); }
接下來看下匯編代碼:
auto_ptr<int> ptr = auto_ptr<int>(new int(10));
...
00771D26 call std::auto_ptr<int>::auto_ptr<int> (07710FAh)
00771D2B lea ecx,[ebp-0D8h]
00771D31 call std::auto_ptr<int>::~auto_ptr<int> (0771159h)
可以看到,它分別調(diào)用了 構(gòu)造函數(shù) 和 析構(gòu)函數(shù),接下來找下 auto_ptr 這兩個(gè)函數(shù)的源碼。
class auto_ptr { private: _Ty* _Myptr; // the wrapped object pointer public: auto_ptr(auto_ptr_ref<_Ty> _Right) noexcept { _Ty* _Ptr = _Right._Ref; _Right._Ref = nullptr; // release old _Myptr = _Ptr; // reset this } ~auto_ptr() noexcept { delete _Myptr; } }
源碼一看就明白了,在構(gòu)造函數(shù)中,將 new int 的地址塞給了內(nèi)部的 _Myptr
指針,在析構(gòu)函數(shù)中對(duì) _Myptr
進(jìn)行 delete
,真好,這樣就不用整天擔(dān)心有沒有加 delete 啦。
值得注意的是,現(xiàn)在 C++ 不推薦這個(gè)了,而是建議使用新增的:shared_ptr,unique_ptr,weak_ptr
, 怎么說呢? auto_ptr 有一個(gè)不好處理的問題,就是現(xiàn)實(shí)開發(fā)中會(huì)出現(xiàn)這么個(gè)場(chǎng)景,多個(gè) ptr 指向同一個(gè) 引用,如下圖:
2. auto_ptr 多引用問題
方式1:
定義三個(gè) ptr,然后包裝同一個(gè) new int
地址,參考代碼如下:
void test() { int* i = new int(10); auto_ptr<int> ptr1(i); auto_ptr<int> ptr2(i); auto_ptr<int> ptr3(i); }
這種寫法有沒有問題呢? 肯定有問題啦,還記得 auto_ptr 的析構(gòu)是 delete 嗎? 對(duì)同一塊內(nèi)存多次 delete 會(huì)拋異常的,如下圖所示:
方式2:
既然定義三個(gè)有問題, 那就用賦值運(yùn)算符=
讓 ptr1,ptr2,ptr3 指向同一個(gè)地址是不是就可以啦? 參考代碼如下:
void test() { int* i = new int(10); auto_ptr<int> ptr1(i); auto_ptr<int> ptr2 = ptr1; auto_ptr<int> ptr3 = ptr2; } int main() { test(); }
那這段代碼有沒有問題呢? 有沒有問題得要看 =
運(yùn)算符是如何重寫的,扒一下源碼看看。
template <class _Other> auto_ptr& operator=(auto_ptr<_Other>& _Right) noexcept { reset(_Right.release()); return *this; } _Ty* release() noexcept { _Ty* _Tmp = _Myptr; _Myptr = nullptr; return _Tmp; }
從源碼看有一個(gè)很惡心的點(diǎn),他會(huì)將 _Right
下的 _Myptr
設(shè)為 nullptr,也就是說此時(shí)的 ptr1 報(bào)廢了,言外之意就是后續(xù)再訪問 ptr1 會(huì)拋 訪問違例。
哈哈,C++里面的專業(yè)術(shù)語叫 控制權(quán)轉(zhuǎn)移。
以上就是一起聊聊C++中的智能指針的詳細(xì)內(nèi)容,更多關(guān)于C++智能指針的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C語言實(shí)現(xiàn)頁面置換算法(FIFO、LRU)
這篇文章主要介紹了通過C語言實(shí)現(xiàn)的兩種頁面置換算法:先進(jìn)先出(FIFO)頁面置換算法和最近最久未使用(LRU)頁面置換算法。文中的代碼具有一定的學(xué)習(xí)或工作價(jià)值,快來跟隨小編學(xué)習(xí)一下吧2021-12-12C語言實(shí)現(xiàn)“幸運(yùn)數(shù)”的實(shí)例詳解
這篇文章主要介紹了C語言實(shí)現(xiàn)“幸運(yùn)數(shù)”的實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-07-07利用Matlab實(shí)現(xiàn)時(shí)域分析功能的示例詳解
利用MATLAB可以方便地進(jìn)行控制系統(tǒng)的時(shí)域分析。這篇文章主要通過簡單的示例為大家介紹了Matlab進(jìn)行時(shí)域分析的具體操作,需要的可以參考一下2023-02-02