網(wǎng)站首頁 編程語言 正文
shared_ptr
采取引用計(jì)數(shù)來表示一塊內(nèi)存被幾個(gè)智能指針?biāo)蚕恚?dāng)引用計(jì)數(shù)為0時(shí),會(huì)自動(dòng)釋放該內(nèi)存,避免了忘記手動(dòng)釋放造成的內(nèi)存泄露問題。采用引用計(jì)數(shù)來管理內(nèi)存對(duì)象的做法是Linux內(nèi)核慣用的手法。
weak_ptr
weak_ptr 設(shè)計(jì)的目的是為配合 shared_ptr 而引入的一種智能指針來協(xié)助 shared_ptr 工作, 它只可以從一個(gè) shared_ptr 或另一個(gè) weak_ptr 對(duì)象構(gòu)造, 它的構(gòu)造和析構(gòu)不會(huì)引起引用記數(shù)的增加或減少。同時(shí)weak_ptr 沒有重載*和->,但可以使用 lock 獲得一個(gè)可用的 shared_ptr 對(duì)象(引用計(jì)數(shù)會(huì)增加1)。
內(nèi)存模型
RefCnt 和 Mdel實(shí)現(xiàn)
template<typename _Ty>
class Mydeletor
{
public:
Mydeletor() = default;
void operator()(_Ty* p)const
{
if (p != NULL)
{
delete[]p;
}
p = NULL;
}
};
template<typename _Ty>
class RefCnt
{
public:
RefCnt(_Ty* p) :ptr(p), Uses(1), Weaks(0)
{
cout <<"RefCnt construct"<<endl;
}
~RefCnt() {}
void IncUses()
{
Uses += 1;
}
void IncWeaks()
{
Weaks += 1;
}
protected:
_Ty* ptr;
std::atomic_int Uses;
std::atomic_int Weaks;
friend class M_shared_ptr<_Ty>;
friend class M_weak_ptr<_Ty>;
};
shared_ptr 實(shí)現(xiàn)
template<typename _Ty,typename _De>
class M_shared_ptr
{
private:
_Ty* Ptr;
RefCnt<_Ty>* Ref;
_De mdeletor;
public:
M_shared_ptr(_Ty* p = nullptr) :Ptr(nullptr),Ref(nullptr)
{
if (p != nullptr)
{
Ptr = p;
Ref = new RefCnt<_Ty>(p);
}
}
M_shared_ptr(const M_shared_ptr& other):Ptr(other.Ptr),Ref(other.Ref)//拷貝構(gòu)造
{
if (Ptr != NULL)
{
Ref->IncUses();
}
}
M_shared_ptr(const M_weak_ptr<_Ty>& other):Ptr(other.GetRef()->ptr),Ref(other.GetRef())//用weak_ptr拷貝構(gòu)造
{
if (Ptr != NULL)
{
Ref->IncUses();
}
}
M_shared_ptr(M_shared_ptr&& other) :Ptr(other.Ptr), Ref(other.Ref)//移動(dòng)構(gòu)造
{
other.Ptr = NULL;
other.Ref = NULL;
}
M_shared_ptr& operator=(const M_shared_ptr& other)//賦值
{
if (this == &other || Ptr == other.Ptr) return *this;//自賦值,直接返回本身
if (Ptr != NULL && --Ref->Uses == 0)//被賦值的智能指針對(duì)象擁有資源,
{ //且該對(duì)象僅被該智能指針擁有
mdeletor(Ptr);//釋放該對(duì)象
if (--Ref->Weaks == 0)//當(dāng)弱引用計(jì)數(shù)為零時(shí)
{
delete Ref;//析構(gòu)引用計(jì)數(shù)對(duì)象
Ref = NULL;
}
}
Ptr = other.Ptr;
Ref = other.Ref;
if (Ptr != NULL)
{
Ref->IncUses();
}
return *this;
}
M_shared_ptr& operator=(M_shared_ptr&& other)//移動(dòng)賦值
{
if (this == &other) return *this;
if (Ptr == other.Ptr && Ptr != NULL)//當(dāng)兩個(gè)智能指針使用同一個(gè)對(duì)象時(shí),且該對(duì)象不為空
{
other.Ptr = NULL;//去掉other的使用權(quán)
other.Ref = NULL;
Ref->Uses -= 1;//強(qiáng)引用計(jì)數(shù)-1
return *this;
}
if (Ptr != NULL && --Ref->Uses == 0)
{
mdeletor(Ptr);
if (--Ref->Weaks == 0)
{
delete Ref;
Ref = NULL;
}
}
Ptr = other.Ptr;
Ref = other.Ref;
other.Ptr = NULL;
other.Ref = NULL;
return *this;
}
~M_shared_ptr()
{
if (Ptr != NULL && --Ref->Uses == 0)
{
mdeletor(Ptr);
if (--Ref->Weaks == 0)
{
delete Ref;
}
}
Ref = NULL;
}
_Ty* get()const
{
return Ptr;
}
_Ty& operator*()
{
return *get();
}
_Ty* operator->()
{
return get();
}
size_t use_count()const
{
if (Ref == NULL) return 0;
return Ref->Uses;
}
void swap(M_shared_ptr& other)
{
std::swap(Ptr, other.Ptr);
std::swap(Ref, other.Ref);
}
operator bool()const
{
return Ptr != NULL;
}
friend class M_weak_ptr<_Ty>;
};
weak_ptr 實(shí)現(xiàn)
template<typename _Ty>
class M_weak_ptr
{
private:
RefCnt<_Ty>* wRef;
public:
size_t use_count()const
{
if (wRef == NULL) return 0;
return wRef->Uses;
}
size_t weak_count()const
{
if (wRef == NULL) return 0;
return wRef->Weaks;
}
RefCnt<_Ty>* GetRef() const
{
return wRef;
}
M_weak_ptr() :wRef(NULL) {}
M_weak_ptr(const M_shared_ptr<_Ty>& other) :wRef(other.Ref)//共享指針構(gòu)造
{
if (wRef!=NULL)
{
wRef->IncWeaks();
}
}
M_weak_ptr(const M_weak_ptr& other) :wRef(other.wRef)//拷貝構(gòu)造
{
if (wRef != NULL)
{
wRef->IncWeaks();
}
}
M_weak_ptr(M_weak_ptr&& other) :wRef(other.wRef)//移動(dòng)構(gòu)造
{
other.wRef = NULL;
}
M_weak_ptr& operator=(const M_weak_ptr& other)
{
if (this == &other||wRef==other.wRef) return *this;//自賦值或者是兩個(gè)指針指向同一個(gè)對(duì)象
if (this != NULL && --wRef->Weaks == 0)//是否自己獨(dú)占對(duì)象
{
delete wRef;
}
wRef = other.wRef;
if (wRef != NULL)
{
wRef->IncUses();
}
return *this;
}
M_weak_ptr& operator=(M_weak_ptr&& other)
{
//1 判斷是否自賦值
if (this == &other) return *this;
//2 判斷是否是指向同一個(gè)對(duì)象的兩個(gè)指針相互賦值
if (wRef == other.wRef && wRef != NULL)//如果是
{
other.wRef = NULL;
wRef->Weaks -= 1;
return *this;
}
//3 兩個(gè)指向不同對(duì)象的指針賦值
if (this != NULL && --wRef->Weaks == 0)//是否自己獨(dú)占對(duì)象
{
delete wRef;//如果獨(dú)有
}
wRef = other.wRef;
other.wRef = NULL;
return *this;
}
M_weak_ptr& operator=(const M_shared_ptr<_Ty>& other)//共享智能指針給弱指針賦值
{
if (wRef == other.Ref) return *this;
if (wRef != NULL && --wRef->Uses == 0)
{
delete wRef;
}
wRef = other.Ref;
if (wRef != NULL)
{
wRef->IncWeaks();
}
return *this;
}
M_weak_ptr& operator=( M_shared_ptr<_Ty>&& other) = delete;
~M_weak_ptr()
{
if (wRef != NULL && --wRef->Weaks == 0)
{
delete wRef;
}
wRef = NULL;
}
bool expired()const//判斷被引用的對(duì)象是否刪除,若刪除則返回真
{
return wRef->Uses == 0;
}
M_shared_ptr<_Ty> lock()const
{
M_shared_ptr<_Ty> tmp;
tmp.Ptr = wRef->ptr;
tmp.Ref = wRef;
tmp.Ref->IncUses();
return tmp;
}
};
shared_from_this()
std::enable_shared_from_this 能讓一個(gè)對(duì)象(假設(shè)其名為 t ,且已被一個(gè) std::shared_ptr 對(duì)象 pt 管理)安全地生成其他額外的 std::shared_ptr 實(shí)例(假設(shè)名為 pt1, pt2, … ) ,它們與 pt 共享對(duì)象 t 的所有權(quán)。
使用原因:
1.把當(dāng)前類對(duì)象作為參數(shù)傳給其他函數(shù)時(shí),為什么要傳遞share_ptr呢?直接傳遞this指針不可以嗎?
一個(gè)裸指針傳遞給調(diào)用者,誰也不知道調(diào)用者會(huì)干什么?假如調(diào)用者delete了該對(duì)象,而share_tr此時(shí)還指向該對(duì)象。
2.這樣傳遞share_ptr可以嗎?share_ptr(this)
這樣會(huì)造成2個(gè)非共享的share_ptr指向一個(gè)對(duì)象,最后造成2次析構(gòu)該對(duì)象。
class T需要繼承enable_shared_from_this才能使用shared_from_this(),具體源碼如下:
namespace boost
{
template<class T> class enable_shared_from_this
{
protected:
enable_shared_from_this()
{
}
enable_shared_from_this(enable_shared_from_this const &)
{
}
enable_shared_from_this & operator=(enable_shared_from_this const &)
{
return *this;
}
~enable_shared_from_this()
{
}
public:
shared_ptr<T> shared_from_this()
{
shared_ptr<T> p( weak_this_ );
BOOST_ASSERT( p.get() == this );
return p;
}
shared_ptr<T const> shared_from_this() const
{
shared_ptr<T const> p( weak_this_ );
BOOST_ASSERT( p.get() == this );
return p;
}
public: // actually private, but avoids compiler template friendship issues
// Note: invoked automatically by shared_ptr; do not call
template<class X, class Y> void _internal_accept_owner( shared_ptr<X> const * ppx, Y * py ) const
{
if( weak_this_.expired() )
{
//shared_ptr通過拷貝構(gòu)造一個(gè)臨時(shí)的shared_ptr,然后賦值給weak_ptr
weak_this_ = shared_ptr<T>( *ppx, py );
}
}
private:
mutable weak_ptr<T> weak_this_;
};
} // namespace boost
template<class Y>
explicit shared_ptr( Y * p ): px( p ), pn( p ) // Y must be complete
{
boost::detail::sp_enable_shared_from_this( this, p, p );
}
template< class X, class Y, class T > inline void sp_enable_shared_from_this( boost::shared_ptr<X> const * ppx, Y const * py, boost::enable_shared_from_this< T > const * pe )
{
if( pe != 0 )
{
//調(diào)用 enable_shared_from_this對(duì)象的函數(shù)
pe->_internal_accept_owner( ppx, const_cast< Y* >( py ) );
}
}
可見該類包含一個(gè)weak_ptr,并在shared_ptr構(gòu)造時(shí),將weak_ptr初始化。shared_from_this()返回一個(gè)用weak_ptr拷貝構(gòu)造的shared_ptr(shared_ptr有此構(gòu)造函數(shù))。
為什么一定是weak_ptr,換成shared_ptr是否可以?
類內(nèi)不能包含指向自身的shared_ptr ,否則它會(huì)無法析構(gòu)。
#include <iostream>
#include <memory>
class Demo
{
public:
Demo()
{
std::cout << "constructor" << std::endl;
}
~Demo()
{
std::cout << "destructor" << std::endl;
}
void StoreDemo(std::shared_ptr<Demo> ptr)
{
m_ptr = ptr;
}
private:
std::shared_ptr<Demo> m_ptr;
};
int main()
{
std::shared_ptr<Demo> d_ptr(new Demo());
d_ptr->StoreDemo(d_ptr); // this line is the bug
return 0;
}
執(zhí)行以上操作后d_ptr的引用計(jì)數(shù)變成2,因此當(dāng)main結(jié)束時(shí),無法執(zhí)行其析構(gòu)函數(shù)。
循環(huán)引用
如果兩個(gè)類互相包含指向?qū)Ψ降膕hared_ptr,就會(huì)造成循環(huán)引用。導(dǎo)致引用計(jì)數(shù)失效,內(nèi)存無法釋放。
#include <iostream>
#include <memory>
class DemoB;
class DemoA
{
public:
DemoA()
{
std::cout << "DemoA()" << std::endl;
}
~DemoA()
{
std::cout << "~DemoA()" << std::endl;
}
void Set_Ptr(std::shared_ptr<DemoB>& ptr)
{
m_ptr_b = ptr;
}
private:
std::shared_ptr<DemoB> m_ptr_b;
};
class DemoB
{
public:
DemoB()
{
std::cout << "DemoB()" << std::endl;
}
~DemoB()
{
std::cout << "~DemoB()" << std::endl;
}
void Set_Ptr(std::shared_ptr<DemoA>& ptr)
{
m_ptr_a = ptr;
}
private:
std::shared_ptr<DemoA> m_ptr_a;
};
int main()
{
std::shared_ptr<DemoA> ptr_a(new DemoA());
std::shared_ptr<DemoB> ptr_b(new DemoB());
ptr_a->Set_Ptr(ptr_b);
ptr_b->Set_Ptr(ptr_a);
std::cout << ptr_a.use_count() << " " << ptr_b.use_count() << std::endl;
return 0;
}
這種情況下 A、B的引用計(jì)數(shù)都是2,因此無法析構(gòu)。
解決該問題,需要將其中一個(gè)類的shared_ptr換成weak_ptr。
原文鏈接:https://blog.csdn.net/zzZhangYiLong/article/details/126696214
相關(guān)推薦
- 2023-05-17 Kotlin開發(fā)中open關(guān)鍵字與類名函數(shù)名和變量名的使用方法淺析_Android
- 2024-03-13 QAobject修改excel字體亂碼問題
- 2022-07-15 Golang配置解析神器go?viper使用詳解_Golang
- 2022-07-13 Docker技術(shù)_Docker與傳統(tǒng)虛擬機(jī)以及傳統(tǒng)容器的差異
- 2022-05-01 使用SQL實(shí)現(xiàn)車流量的計(jì)算的示例代碼_MsSql
- 2022-10-09 xshell5使用ssh連接阿里云服務(wù)器的實(shí)現(xiàn)步驟_Linux
- 2022-11-23 Python多線程使用方法詳細(xì)講解_python
- 2022-12-06 靜態(tài)pod?創(chuàng)建使用示例詳解_docker
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支