C++ 智能指針代碼解析
前言
如果在程序中使用new從堆分配內(nèi)存,等到不再需要時(shí),應(yīng)使用delete將其釋放,C++引入了智能指針auto_ptr,以幫助自動(dòng)完成這個(gè)過(guò)程,但是aoto_ptr也有其局限性,因此從Boost庫(kù)中又引入了三種智能指針unique_ptr shared_ptr weak_ptr。
1,aoto_ptr
// ConsoleApplication1.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。 // #include "stdafx.h" #include <memory> #include <string> #include <iostream> #include <ostream> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { auto_ptr<string> ptr1(new string("this is ptr!")); auto_ptr<string> ptr2; ptr2 = ptr1; cout << &ptr2<<endl; cout << *ptr2 << endl; return 0; }
- output :
003AFBC0
this is ptr!
但是如果輸出的是ptr1,程序會(huì)如何呢?
#include "stdafx.h" #include <memory> #include <string> #include <iostream> #include <ostream> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { auto_ptr<string> ptr1(new string("this is ptr!")); auto_ptr<string> ptr2; ptr2 = ptr1; cout << &ptr1 <<endl; cout << *ptr1 << endl; #這一步程序會(huì)崩潰 return 0; }
崩潰原因: 首先ptr2 = ptr1表示ptr1將訪問(wèn)的權(quán)限給了ptr2,同時(shí)意味了ptr1已經(jīng)沒(méi)有訪問(wèn)字符串的權(quán)限,因此會(huì)報(bào)錯(cuò)。
那如何解決這個(gè)問(wèn)題呢?引入了unique_ptr
2,unique_ptr
#include "stdafx.h" #include <memory> #include <string> #include <iostream> #include <ostream> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { unique_ptr<string> ptr1(new string("this is unique_ptr")); unique_ptr<string> ptr2; ptr2 = ptr1; #這一步編譯器會(huì)報(bào)錯(cuò) return 0; }
unique_ptr 替代auto_ptr實(shí)現(xiàn)獨(dú)占式,可以理解成,同一時(shí)刻只能有一個(gè)unique_ptr指向給定對(duì)象,unique_ptr對(duì)象始終是關(guān)聯(lián)的原始指針的唯一所有者。無(wú)法復(fù)制unique_ptr對(duì)象,它只能移動(dòng)。(這樣可以保證,不會(huì)出現(xiàn)auto_ptr那樣運(yùn)行時(shí)會(huì)出現(xiàn)的隱藏內(nèi)存崩潰問(wèn)題)
int _tmain(int argc, _TCHAR* argv[]) { unique_ptr<string> ptr1(new string("this is unique_ptr")); unique_ptr<string> ptr2; cout << &ptr1 << endl; unique_ptr<string> ptr3(new string("other unique_ptr")); cout << &ptr3 << endl; cout << *ptr3 << endl; return 0; }
- output:
00D9F8B4
00D9F89C
other unique_ptr
3,share_ptr
// ConsoleApplication1.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。 // #include "stdafx.h" #include <memory> #include <string> #include <iostream> #include <ostream> using namespace std; class base{ public: base() { cout << "begin..." << endl; }; ~base() { cout << "end..." << endl; } }; int _tmain(int argc, _TCHAR* argv[]) { base *a = new base(); shared_ptr<base> ptr1(a); //shared_ptr<base> ptr2(a); ## 如果加上這句程序會(huì)崩潰,雙重管理陷阱,a對(duì)象被刪除了兩次 return 0; }
- output:
begin...
end...
- share_ptr的循環(huán)陷阱
#include "stdafx.h" #include <memory> #include <string> #include <iostream> #include <ostream> using namespace std; class CB; class CA { public: CA() { cout << "CA call ..."<< endl; } ~CA() { cout << "~CA call..."<< endl; } void setPtr(shared_ptr<CB> &ptr) { m_ptr_b = ptr; } int getCount() { return m_ptr_b.use_count(); } private: shared_ptr<CB> m_ptr_b; }; class CB { public: CB() { cout << "CB call..." << endl; } ~CB() { cout << "~CB call..." << endl; } void setPtr(shared_ptr<CA> ptr) { m_ptr_a = ptr; } int getCount() { return m_ptr_a.use_count(); } private: shared_ptr<CA> m_ptr_a; }; int _tmain(int argc, _TCHAR* argv[]) { shared_ptr<CA> ptr_a(new CA); shared_ptr<CB> ptr_b(new CB); cout << " CA count is : " << ptr_a->getCount()<<endl; cout << "CB count is:" << ptr_b->getCount()<< endl; ptr_a->setPtr(ptr_b); ptr_b->setPtr(ptr_a); cout << " CA count is : " << ptr_a->getCount() << endl; cout << "CB count is:" << ptr_b->getCount() << endl; return 0; }
上面這段程序的思路用下面張圖可以清晰的表示
圖片和代碼主要參考的是這篇很棒的博文:智能指針(三):weak_ptr淺析
運(yùn)行結(jié)果后發(fā)現(xiàn)并沒(méi)有調(diào)用析構(gòu)函數(shù)釋放內(nèi)存,以后存在內(nèi)存泄漏的風(fēng)險(xiǎn)
那如何去解決這個(gè)問(wèn)題呢?,可以通過(guò)引入weak_ptr來(lái)解決,但是weak_ptr需要與share_ptr配合使用
4, weak_ptr
通過(guò)在兩個(gè)類(lèi)中的一個(gè)成員變量改為weak_ptr對(duì)象,因?yàn)閣eak_ptr不會(huì)增加引用計(jì)數(shù),使得引用形不成環(huán),最后就可以正常的釋放內(nèi)部的對(duì)象,不會(huì)造成內(nèi)存泄漏
class CB { public: CB() { cout << "CB call..." << endl; } ~CB() { cout << "~CB call..." << endl; } void setPtr(shared_ptr<CA> ptr) { m_ptr_a = ptr; } int getCount() { return m_ptr_a.use_count(); } private: ///shared_ptr<CA> m_ptr_a; weak_ptr<CA> m_ptr_a; ## 改為weak_ptr對(duì)象 };
總結(jié)
遇到這類(lèi)新的概念或者方法時(shí),一定要不嫌麻煩的一行一行代碼的去敲,在敲的過(guò)程中去理解吸收,如果只看不實(shí)踐,很有可能理解不深刻,無(wú)法體會(huì)到其中的原理和機(jī)制,所以對(duì)待問(wèn)題一定要沉下心來(lái)多實(shí)踐。
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
C++對(duì)象的淺復(fù)制和深復(fù)制詳解及簡(jiǎn)單實(shí)例
這篇文章主要介紹了C++對(duì)象的淺復(fù)制和深復(fù)制詳解及簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-04-04win10環(huán)境下C++ vs2015編譯opencv249的教程
這篇文章主要介紹了win10環(huán)境下C++ vs2015編譯opencv249的教程,本文分步驟給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03C++實(shí)現(xiàn)圖書(shū)館系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)圖書(shū)館系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03C++語(yǔ)言const 關(guān)鍵字使用方法圖文詳解
在類(lèi)中,如果你不希望某些數(shù)據(jù)被修改,可以使用const關(guān)鍵字加以限定。const 可以用來(lái)修飾成員變量、成員函數(shù)以及對(duì)象2020-01-01C++中的多態(tài)與虛函數(shù)的內(nèi)部實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇C++中的多態(tài)與虛函數(shù)的內(nèi)部實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12解決Qt設(shè)置QTextEdit行高的問(wèn)題
這篇文章介紹了Qt設(shè)置QTextEdit行高的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04利用C++開(kāi)發(fā)一個(gè)protobuf動(dòng)態(tài)解析工具
數(shù)據(jù)庫(kù)中存儲(chǔ)的protobuf序列化的內(nèi)容,有時(shí)候查問(wèn)題想直接解析查看內(nèi)容。很多編碼在網(wǎng)上很容易找到編解碼工具,但protobuf沒(méi)有找到編解碼工具,可能這樣的需求比較少吧,那就自己用C++實(shí)現(xiàn)一個(gè),感興趣的可以了解一下2023-01-01C語(yǔ)言 哈希查找詳解(哈希表的創(chuàng)建、處理沖突、查找等)
哈希表是一種非常重要的數(shù)據(jù)結(jié)構(gòu),并在大量的計(jì)算機(jī)科學(xué)和工程應(yīng)用中發(fā)揮重要作用,了解哈希表的原理和實(shí)現(xiàn)方式,將有助于我們更好地理解這個(gè)數(shù)據(jù)結(jié)構(gòu)及如何應(yīng)用它來(lái)解決實(shí)際問(wèn)題,這篇文章主要介紹了C語(yǔ)言 哈希查找(哈希表的創(chuàng)建、處理沖突、查找等),需要的朋友可以參考下2024-01-01