C++中智能指針最常用的shared_ptr和unique_ptr
shared_ptr
基本用法: 可以通過構(gòu)造函數(shù), make_shared<T>輔助函數(shù)和reset()方法來初始化shared_ptr
1. 初始化方法
shared_ptr<int> p1(new int(1)); shared_ptr<int> p2 = p1; shared_ptr<int> p3; p3.reset(new int(1)); shared_ptr<int> p4 = make_shared<int>(int(5));
優(yōu)先使用make_shared來構(gòu)造, 更加高效
不能用一個(gè)原始指針直接賦值智能指針, 以下方式是錯(cuò)誤的
shared_ptr<int> p5=new int(1); //error
2.獲取智能指針的原始指針: 通過get方法
shared_ptr<int> ptr = make_shared<int>(int(5)); int *p=ptr.get();
3.指定刪除器:自定義指針銷毀方式
void ptr_deleter(const int*p) { delete p; } shared_ptr<int> p(new int, ptr_deleter);
第二個(gè)參數(shù)指定刪除器(一個(gè)可調(diào)用對(duì)象, 其中參數(shù)為該類型的指針, 如上面為int*)
當(dāng)shared_ptr引用計(jì)數(shù)為0時(shí), 調(diào)用傳入的而不是默認(rèn)的刪除器來釋放對(duì)象的內(nèi)存
當(dāng)用shared_ptr管理動(dòng)態(tài)數(shù)組時(shí), 需要指定刪除器, 因?yàn)閟hared_ptr默認(rèn)刪除器不支持?jǐn)?shù)組對(duì)象
如下使用lambda表達(dá)式作為刪除器
shared_ptr<int> p(new int[10],[](int*p){delete []p;});
通過default_delete作為刪除器, 同時(shí)封裝一個(gè)make_shared_array函數(shù)來支持?jǐn)?shù)組
template<typename T> shared_ptr<T> make_shared_array(int size) { return shared_ptr<T>(new T[size],default_delete<T[]>()); }
(自測(cè))貌似這樣也支持?jǐn)?shù)組
shared_ptr<int[]> ptr(new int[10]);
使用shared_ptr注意
(1)不要用一個(gè)原始指針初始化多個(gè)shared_ptr
int *ptr = new int; shared_ptr<int> p1(ptr); shared_ptr<int> p2(ptr); //錯(cuò)誤
(2)不要在函數(shù)實(shí)參中創(chuàng)建shared_ptr
function(shared_ptr<int>(new int),g());
參數(shù)的計(jì)算順序可能沒有固定順序, 若是new int后執(zhí)行g(shù)()拋出異常, 則shared_ptr還沒有創(chuàng)建, 則new int內(nèi)存泄漏了
(3)不要用this指針構(gòu)造shared_ptr作為返回值
class A { public: shared_ptr<A> get_self() { return shared_ptr<A>(this); } ~A() { cout << ("destructor") << endl; } }; int main() { shared_ptr<A> p1(new A); shared_ptr<A> p2 = p1->get_self(); return 0; }
destructor
destructor
以上代碼p1和p2相當(dāng)于同一個(gè)new A初始化, 會(huì)shared_ptr銷毀時(shí), 會(huì)重復(fù)析構(gòu)
正確做法:
讓該類繼承enable_shared_from_this<>, 同時(shí)調(diào)用shared_from_this()返回
class A :public enable_shared_from_this<A> //繼承 { public: shared_ptr<A> get_self() { return shared_from_this(); //調(diào)用該函數(shù) } ~A() { cout << ("destructor") << endl; } }; int main() { shared_ptr<A> p1(new A); shared_ptr<A> p2 = p1->get_self(); return 0; }
destructor
只要用shared_ptr, 調(diào)用的成員函數(shù)里都不能使用this構(gòu)造, 否則都會(huì)出錯(cuò)
class A { public: void test() { shared_ptr<A>(this); //錯(cuò)誤 } ~A() { cout<<( "destructor" )<<endl; } }; shared_ptr<A> p(new A); p->test()
另外, 不要在構(gòu)造函數(shù)里使用shared_from_this
(4)避免循環(huán)引用
以下代碼會(huì)由于循環(huán)引用, 引用計(jì)數(shù)值都為1, 導(dǎo)致兩個(gè)指針都不會(huì)析構(gòu)
class A; class B; class A { public: shared_ptr<B> b_ptr; ~A() { cout << ("A destructor") << endl; } }; class B { public: shared_ptr<A> a_ptr; ~B() { cout << ("B destructor") << endl; } }; int main() { shared_ptr<A> a_p(new A); shared_ptr<B> b_p(new B); a_p->b_ptr=b_p; b_p->a_ptr=a_p; }
//沒有輸出
unique_ptr
unique_ptr不允許復(fù)制, 不允許其他的智能指針共享其內(nèi)部的指針, 但可以轉(zhuǎn)移
unique_ptr<int> ptr(new int); // unique_ptr<int> ptr2=ptr; error 不可以賦值 unique_ptr<int> ptr3=move(ptr); //用move進(jìn)行轉(zhuǎn)移 assert(ptr!=nullptr); //轉(zhuǎn)移后ptr為nullptr
自定義make_unique函數(shù)且讓其支持定長數(shù)組
思路
不是數(shù)組, 返回unique_ptr<T>
是數(shù)組且非定長數(shù)組, 返回unique_ptr<T>, 即不應(yīng)該調(diào)用make_unique<T[10]>(10)而是make_unique<T[]>(10)
最后過濾掉該定長數(shù)組(函數(shù)聲明為delete)
// !is_array_v確定不是數(shù)組, 返回unique_ptr<T> template<typename T,typename ...Args> enable_if_t<!is_array_v<T>,unique_ptr<T>> make_unique_(Args&&...args) { return unique_ptr<T>( new T(forward<Args>(args)...)); } //定長數(shù)組如T[10], 不應(yīng)該調(diào)用make_unique<T[10]>(10);而是make_unique<T[]>(10); // is_array_v確定是數(shù)組且!extent_v<T>確定非定長數(shù)組, 返回unique_ptr<T> template<typename T,typename ...Args> enable_if_t<is_array_v<T>&&!extent_v<T>,unique_ptr<T>> make_unique_(size_t size) { using U=remove_extent_t<T>; return unique_ptr<T>( new U[size]); } //否之過濾掉該定長數(shù)組 template<typename T,typename ...Args> enable_if_t<extent_v<T>,void> make_unique_(Args&&...)=delete;
unique_ptr<int> ptr= make_unique_<int>(10); unique_ptr<int[]> ptr1= make_unique_<int[]>(10);
不過unique_ptr本身也支持?jǐn)?shù)組, shared_ptr自測(cè)也支持, 如下
unique_ptr<A[]> ptr1(new A[10]); shared_ptr<A[]> ptr2(new A[10]);
unique_ptr也支持刪除器, 但和shared_ptr有區(qū)別, 要指定刪除器類型
shared_ptr<A> p1(new A[10],[](A*p){delete []p;}); // unique_ptr<A> p2(new A[10],[](A*p){delete []p;}); 錯(cuò)誤 unique_ptr<A,void(*)(A*)> p2(new A[10],[](A*p){delete []p;}); //正確
如果希望lambda刪除器捕獲變量, 則需要用function包裝
unique_ptr<A,void(*)(A*)> p1(new A[10],[&](A*p){delete []p;}); //錯(cuò)誤 unique_ptr<A,function<void(A*)>> p2(new A[10],[&](A*p){delete []p;}); //正確
到此這篇關(guān)于C++中智能指針最常用的shared_ptr和unique_ptr的文章就介紹到這了,更多相關(guān)C++ shared_ptr和unique_ptr內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++實(shí)現(xiàn)LeetCode(6.字型轉(zhuǎn)換字符串)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(6.字型轉(zhuǎn)換字符串),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07C語言數(shù)據(jù)結(jié)構(gòu)與算法之圖的遍歷(一)
這篇文章主要是介紹了利用深度優(yōu)先算法實(shí)現(xiàn)圖的遍歷,文中利用圖文詳細(xì)的介紹了實(shí)現(xiàn)步驟,對(duì)我們學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法有一定的幫助,需要的朋友可以參考一下2021-12-12適合初學(xué)者的C語言數(shù)據(jù)類型的講解
在 C 語言中,數(shù)據(jù)類型指的是用于聲明不同類型的變量或函數(shù)的一個(gè)廣泛的系統(tǒng)。變量的類型決定了變量存儲(chǔ)占用的空間,以及如何解釋存儲(chǔ)的位模式。2022-04-04C語言中獲取和改變目錄的相關(guān)函數(shù)總結(jié)
這篇文章主要介紹了C語言中獲取和改變目錄的相關(guān)函數(shù)總結(jié),包括getcwd()函數(shù)和chdir()函數(shù)以及chroot()函數(shù)的使用方法,需要的朋友可以參考下2015-09-09OpenCV 視頻中火焰檢測(cè)識(shí)別實(shí)踐
本文主要介紹了OpenCV 視頻中火焰檢測(cè)識(shí)別,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09Cmake中強(qiáng)大的輸出函數(shù)message示例解析
這篇文章主要介紹了Cmake中強(qiáng)大的輸出函數(shù)message解析,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-05-05