網站首頁 編程語言 正文
shared_ptr
基本用法: 可以通過構造函數, make_shared<T>輔助函數和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));
優先使用make_shared來構造, 更加高效
不能用一個原始指針直接賦值智能指針, 以下方式是錯誤的
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);
第二個參數指定刪除器(一個可調用對象, 其中參數為該類型的指針, 如上面為int*)
當shared_ptr引用計數為0時, 調用傳入的而不是默認的刪除器來釋放對象的內存
當用shared_ptr管理動態數組時, 需要指定刪除器, 因為shared_ptr默認刪除器不支持數組對象
如下使用lambda表達式作為刪除器
shared_ptr<int> p(new int[10],[](int*p){delete []p;});
通過default_delete作為刪除器, 同時封裝一個make_shared_array函數來支持數組
template<typename T>
shared_ptr<T> make_shared_array(int size)
{
return shared_ptr<T>(new T[size],default_delete<T[]>());
}
(自測)貌似這樣也支持數組
shared_ptr<int[]> ptr(new int[10]);
使用shared_ptr注意
(1)不要用一個原始指針初始化多個shared_ptr
int *ptr = new int;
shared_ptr<int> p1(ptr);
shared_ptr<int> p2(ptr); //錯誤
(2)不要在函數實參中創建shared_ptr
function(shared_ptr<int>(new int),g());
參數的計算順序可能沒有固定順序, 若是new int后執行g()拋出異常, 則shared_ptr還沒有創建, 則new int內存泄漏了
(3)不要用this指針構造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相當于同一個new A初始化, 會shared_ptr銷毀時, 會重復析構
正確做法:
讓該類繼承enable_shared_from_this<>, 同時調用shared_from_this()返回
class A :public enable_shared_from_this<A> //繼承
{
public:
shared_ptr<A> get_self()
{
return shared_from_this(); //調用該函數
}
~A()
{
cout << ("destructor") << endl;
}
};
int main()
{
shared_ptr<A> p1(new A);
shared_ptr<A> p2 = p1->get_self();
return 0;
}
destructor
只要用shared_ptr, 調用的成員函數里都不能使用this構造, 否則都會出錯
class A
{
public:
void test()
{
shared_ptr<A>(this); //錯誤
}
~A()
{
cout<<( "destructor" )<<endl;
}
};
shared_ptr<A> p(new A);
p->test()
另外, 不要在構造函數里使用shared_from_this
(4)避免循環引用
以下代碼會由于循環引用, 引用計數值都為1, 導致兩個指針都不會析構
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不允許復制, 不允許其他的智能指針共享其內部的指針, 但可以轉移
unique_ptr<int> ptr(new int);
// unique_ptr<int> ptr2=ptr; error 不可以賦值
unique_ptr<int> ptr3=move(ptr); //用move進行轉移
assert(ptr!=nullptr); //轉移后ptr為nullptr
自定義make_unique函數且讓其支持定長數組
思路
不是數組, 返回unique_ptr<T>
是數組且非定長數組, 返回unique_ptr<T>, 即不應該調用make_unique<T[10]>(10)而是make_unique<T[]>(10)
最后過濾掉該定長數組(函數聲明為delete)
// !is_array_v確定不是數組, 返回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)...));
}
//定長數組如T[10], 不應該調用make_unique<T[10]>(10);而是make_unique<T[]>(10);
// is_array_v確定是數組且!extent_v<T>確定非定長數組, 返回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]);
}
//否之過濾掉該定長數組
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本身也支持數組, shared_ptr自測也支持, 如下
unique_ptr<A[]> ptr1(new A[10]);
shared_ptr<A[]> ptr2(new A[10]);
unique_ptr也支持刪除器, 但和shared_ptr有區別, 要指定刪除器類型
shared_ptr<A> p1(new A[10],[](A*p){delete []p;});
// unique_ptr<A> p2(new A[10],[](A*p){delete []p;}); 錯誤
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;}); //錯誤
unique_ptr<A,function<void(A*)>> p2(new A[10],[&](A*p){delete []p;}); //正確
原文鏈接:https://blog.csdn.net/TOPEE362/article/details/126353662
相關推薦
- 2021-10-09 C#?將Excel轉為PDF時自定義表格紙張大小的代碼思路_C#教程
- 2022-07-18 Element-UI:el-table樣式修改
- 2022-11-14 Android開發RecyclerView單獨刷新使用技巧_Android
- 2022-08-17 C++詳解Primer文本查詢程序的實現_C 語言
- 2022-10-28 Pandas實現兩個表的連接功能的方法詳解_python
- 2022-12-21 Android?RecyclerView四級緩存源碼層詳細分析_Android
- 2023-02-01 Python中使用zip函數的七重境界解析_python
- 2022-04-19 C#中Task.ContinueWith連續任務使用實例_C#教程
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支