欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++智能指針shared_ptr與weak_ptr的實現(xiàn)分析

 更新時間:2022年09月09日 14:44:44   作者:zzZhangYiLong  
shared_ptr是一個標準的共享所有權的智能指針,允許多個指針指向同一個對象,定義在 memory 文件中,命名空間為 std,這篇文章主要介紹了C++ 中 shared_ptr weak_ptr,需要的朋友可以參考下

shared_ptr

采取引用計數(shù)來表示一塊內(nèi)存被幾個智能指針所共享,當引用計數(shù)為0時,會自動釋放該內(nèi)存,避免了忘記手動釋放造成的內(nèi)存泄露問題。采用引用計數(shù)來管理內(nèi)存對象的做法是Linux內(nèi)核慣用的手法。

weak_ptr

weak_ptr 設計的目的是為配合 shared_ptr 而引入的一種智能指針來協(xié)助 shared_ptr 工作, 它只可以從一個 shared_ptr 或另一個 weak_ptr 對象構造, 它的構造和析構不會引起引用記數(shù)的增加或減少。同時weak_ptr 沒有重載*和->,但可以使用 lock 獲得一個可用的 shared_ptr 對象(引用計數(shù)會增加1)。

內(nèi)存模型

RefCnt 和 Mdel實現(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 實現(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)//拷貝構造
	{
		if (Ptr != NULL)
		{
			Ref->IncUses();
		}
	}
	M_shared_ptr(const M_weak_ptr<_Ty>& other):Ptr(other.GetRef()->ptr),Ref(other.GetRef())//用weak_ptr拷貝構造
	{
		if (Ptr != NULL)
		{
			Ref->IncUses();
		}
	}
	M_shared_ptr(M_shared_ptr&& other) :Ptr(other.Ptr), Ref(other.Ref)//移動構造
	{
		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)//被賦值的智能指針對象擁有資源,
		{                                   //且該對象僅被該智能指針擁有
			mdeletor(Ptr);//釋放該對象
			if (--Ref->Weaks == 0)//當弱引用計數(shù)為零時
			{
				delete Ref;//析構引用計數(shù)對象
				Ref = NULL;
			}
		}
		Ptr = other.Ptr;
		Ref = other.Ref;
		if (Ptr != NULL)
		{
			Ref->IncUses();
		}
		return *this;
	}
	M_shared_ptr& operator=(M_shared_ptr&& other)//移動賦值
	{
		if (this == &other)  return *this;
		if (Ptr == other.Ptr && Ptr != NULL)//當兩個智能指針使用同一個對象時,且該對象不為空
		{
			other.Ptr = NULL;//去掉other的使用權
			other.Ref = NULL;
			Ref->Uses -= 1;//強引用計數(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 實現(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)//共享指針構造
	{
		if (wRef!=NULL)
		{
			wRef->IncWeaks();
		}
	}
	M_weak_ptr(const M_weak_ptr& other) :wRef(other.wRef)//拷貝構造
	{
		if (wRef != NULL)
		{
			wRef->IncWeaks();
		}
	}
	M_weak_ptr(M_weak_ptr&& other) :wRef(other.wRef)//移動構造
	{
		other.wRef = NULL;
	}
	M_weak_ptr& operator=(const M_weak_ptr& other)
	{
		if (this == &other||wRef==other.wRef)  return *this;//自賦值或者是兩個指針指向同一個對象
		if (this != NULL && --wRef->Weaks == 0)//是否自己獨占對象
		{
			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 判斷是否是指向同一個對象的兩個指針相互賦值
		if (wRef == other.wRef && wRef != NULL)//如果是
		{
			other.wRef = NULL;
			wRef->Weaks -= 1;
			return *this;
		}
		//3 兩個指向不同對象的指針賦值
		if (this != NULL && --wRef->Weaks == 0)//是否自己獨占對象
		{
			delete wRef;//如果獨有
		}
		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//判斷被引用的對象是否刪除,若刪除則返回真
	{
		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 能讓一個對象(假設其名為 t ,且已被一個 std::shared_ptr 對象 pt 管理)安全地生成其他額外的 std::shared_ptr 實例(假設名為 pt1, pt2, … ) ,它們與 pt 共享對象 t 的所有權。

使用原因:

1.把當前類對象作為參數(shù)傳給其他函數(shù)時,為什么要傳遞share_ptr呢?直接傳遞this指針不可以嗎?

一個裸指針傳遞給調(diào)用者,誰也不知道調(diào)用者會干什么?假如調(diào)用者delete了該對象,而share_tr此時還指向該對象。

2.這樣傳遞share_ptr可以嗎?share_ptr(this)

這樣會造成2個非共享的share_ptr指向一個對象,最后造成2次析構該對象。

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通過拷貝構造一個臨時的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對象的函數(shù) 
      pe->_internal_accept_owner( ppx, const_cast< Y* >( py ) );
    }
}

可見該類包含一個weak_ptr,并在shared_ptr構造時,將weak_ptr初始化。shared_from_this()返回一個用weak_ptr拷貝構造的shared_ptr(shared_ptr有此構造函數(shù))。

為什么一定是weak_ptr,換成shared_ptr是否可以?

類內(nèi)不能包含指向自身的shared_ptr ,否則它會無法析構。

#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的引用計數(shù)變成2,因此當main結束時,無法執(zhí)行其析構函數(shù)。

循環(huán)引用

如果兩個類互相包含指向?qū)Ψ降膕hared_ptr,就會造成循環(huán)引用。導致引用計數(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的引用計數(shù)都是2,因此無法析構。

解決該問題,需要將其中一個類的shared_ptr換成weak_ptr。

到此這篇關于C++智能指針shared_ptr與weak_ptr的實現(xiàn)分析的文章就介紹到這了,更多相關C++ shared_ptr與weak_ptr內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • C語言深入講解鏈表的使用

    C語言深入講解鏈表的使用

    當我們在寫一段代碼時,如果要頻繁的在一塊區(qū)域進行插入或者刪除操作時,會發(fā)現(xiàn)用數(shù)組實現(xiàn)會比較復雜,這時候我們就要用另一種數(shù)據(jù)結構,鏈表來實現(xiàn)
    2022-05-05
  • C++中NULL與nullptr的區(qū)別對比

    C++中NULL與nullptr的區(qū)別對比

    nullptr是c++11中的關鍵字,下面這篇文章主要介紹了C++中NULL與nullptr區(qū)別的相關資料,對大家來說還是挺實用的,需要的朋友可以參考下
    2021-05-05
  • OpenCV 視頻中火焰檢測識別實踐

    OpenCV 視頻中火焰檢測識別實踐

    本文主要介紹了OpenCV 視頻中火焰檢測識別,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • linux c程序中獲取shell腳本輸出的實現(xiàn)方法

    linux c程序中獲取shell腳本輸出的實現(xiàn)方法

    以下是對在linux下c程序中獲取shell腳本輸出的實現(xiàn)方法進行了詳細的分析介紹,需要的朋友可以過來參考下
    2013-08-08
  • C++ OpenCV制作黑客帝國風格的照片

    C++ OpenCV制作黑客帝國風格的照片

    這篇文章主要介紹了如何通過C++ OpenCV制作出黑客帝國風格的照片,文中的示例代碼講解詳細,對我們學習OpenCV有一定幫助,需要的可以參考一下
    2022-01-01
  • 從使用角度解讀c++20 協(xié)程示例

    從使用角度解讀c++20 協(xié)程示例

    類比線程,線程是個函數(shù),把這個函數(shù)交給 創(chuàng)建線程的api,然后這個函數(shù)就變成線程了,這個函數(shù)本身沒有任何特殊的地方,就是普通函數(shù),這篇文章主要介紹了從使用角度解讀c++20 協(xié)程示例,需要的朋友可以參考下
    2023-01-01
  • 基于C語言實現(xiàn)五子棋游戲完整實例代碼

    基于C語言實現(xiàn)五子棋游戲完整實例代碼

    這篇文章主要介紹了基于C語言實現(xiàn)五子棋游戲完整實例代碼,相信對于學習游戲開發(fā)的朋友會有一定的幫助與借鑒價值,需要的朋友可以參考下
    2014-08-08
  • C++實現(xiàn)LeetCode(13.羅馬數(shù)字轉(zhuǎn)化成整數(shù))

    C++實現(xiàn)LeetCode(13.羅馬數(shù)字轉(zhuǎn)化成整數(shù))

    這篇文章主要介紹了C++實現(xiàn)LeetCode(13.羅馬數(shù)字轉(zhuǎn)化成整數(shù)),本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • 解析VScode在Windows環(huán)境下c_cpp_properties.json文件配置問題(推薦)

    解析VScode在Windows環(huán)境下c_cpp_properties.json文件配置問題(推薦)

    這篇文章主要介紹了解析VScode在Windows環(huán)境下c_cpp_properties.json文件配置問題,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05
  • C語言中指針常量和常量指針的區(qū)別

    C語言中指針常量和常量指針的區(qū)別

    本文主要介紹了C語言中指針常量和常量指針的區(qū)別,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01

最新評論