广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++智能指针shared_ptr与weak_ptr的实现分析
  • 545
分享到

C++智能指针shared_ptr与weak_ptr的实现分析

2024-04-02 19:04:59 545人浏览 安东尼
摘要

目录shared_ptrweak_ptr内存模型RefCnt 和 Mdel实现shared_ptr 实现weak_ptr 实现shared_from_this()循环引用shared

shared_ptr

采取引用计数来表示一块内存被几个智能指针所共享,当引用计数为0时,会自动释放该内存,避免了忘记手动释放造成的内存泄露问题。采用引用计数来管理内存对象的做法是linux内核惯用的手法。

weak_ptr

weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少。同时weak_ptr 没有重载*和->,但可以使用 lock 获得一个可用的 shared_ptr 对象(引用计数会增加1)。

内存模型

RefCnt 和 Mdel实现

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 实现

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)//当弱引用计数为零时
			{
				delete Ref;//析构引用计数对象
				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;//强引用计数-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 实现

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.把当前类对象作为参数传给其他函数时,为什么要传递share_ptr呢?直接传递this指针不可以吗?

一个裸指针传递给调用者,谁也不知道调用者会干什么?假如调用者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 )
    {
      //调用 enable_shared_from_this对象的函数 
      pe->_internal_accept_owner( ppx, const_cast< Y* >( py ) );
    }
}

可见该类包含一个weak_ptr,并在shared_ptr构造时,将weak_ptr初始化。shared_from_this()返回一个用weak_ptr拷贝构造的shared_ptr(shared_ptr有此构造函数)。

为什么一定是weak_ptr,换成shared_ptr是否可以?

类内不能包含指向自身的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;
}

执行以上操作后d_ptr的引用计数变成2,因此当main结束时,无法执行其析构函数。

循环引用

如果两个类互相包含指向对方的shared_ptr,就会造成循环引用。导致引用计数失效,内存无法释放。

#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的引用计数都是2,因此无法析构。

解决该问题,需要将其中一个类的shared_ptr换成weak_ptr。

到此这篇关于c++智能指针shared_ptr与weak_ptr的实现分析的文章就介绍到这了,更多相关C++ shared_ptr与weak_ptr内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++智能指针shared_ptr与weak_ptr的实现分析

本文链接: https://www.lsjlt.com/news/167256.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++智能指针shared_ptr与weak_ptr的实现分析
    目录shared_ptrweak_ptr内存模型RefCnt 和 Mdel实现shared_ptr 实现weak_ptr 实现shared_from_this()循环引用shared...
    99+
    2022-11-13
  • C语言 智能指针 shared_ptr 和 weak_ptr
    weak_ptr引入可以解决shared_ptr交叉引用时无法释放资源的问题。 示例代码: #include <iostream> #include <memory...
    99+
    2022-11-13
  • 浅析Boost智能指针:scoped_ptr shared_ptr weak_ptr
    一. scoped_ptrboost::scoped_ptr和std::auto_ptr非常类似,是一个简单的智能指针,它能够保证在离开作用域后对象被自动释放。下列代码演示了该指针的...
    99+
    2022-11-15
    scoped_ptr shared_ptr weak_ptr
  • C++11中的智能指针shared_ptr、weak_ptr源码解析
    目录1、前言2、源码准备3、智能指针概念4、源码解析4.1、shared_ptr解析4.1.1、shared_ptr4.1.2、__shared_ptr4.1.3、__shared_...
    99+
    2022-11-12
  • C语言智能指针shared_ptr和weak_ptr怎么用
    这篇文章主要讲解了“C语言智能指针shared_ptr和weak_ptr怎么用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C语言智能指针shared_ptr和weak_ptr怎么用”吧!w...
    99+
    2023-06-30
  • C语言智能指针之weak_ptr浅析
    目录前言使用环境测试过程现象分析总结前言 weak_ptr这个指针天生一副“小弟”的模样,也是在C++11的时候引入的标准库,它的出现完全是为了弥补它老大shared_ptr天生有缺...
    99+
    2022-11-12
  • C++中Boost的智能指针weak_ptr
    循环引用: 引用计数是一种便利的内存管理机制,但它有一个很大的缺点,那就是不能管理循环引用的对象。一个简单的例子如下: #include <string> #includ...
    99+
    2022-11-13
  • C++中Boost的智能指针shared_ptr
    boost::scoped_ptr虽然简单易用,但它不能共享所有权的特性却大大限制了其使用范围,而boost::shared_ptr可以解决这一局限。顾名思义,boost::shar...
    99+
    2022-11-13
  • C++11的shared_ptr与weak_ptr示例分析
    这篇文章主要讲解了“C++11的shared_ptr与weak_ptr示例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++11的shared_ptr与weak_ptr示例分析”吧!实...
    99+
    2023-06-19
  • C++智能指针之shared_ptr的具体使用
    目录std::shared_ptr概念shared_ptr模板类shared_ptr的构造和析构shared_ptr赋值make_shared计数线程安全?enable_shared...
    99+
    2022-11-13
  • C++中智能指针最常用的shared_ptr和unique_ptr
    目录shared_ptr使用shared_ptr注意unique_ptrshared_ptr 基本用法: 可以通过构造函数, make_shared<T>辅助函数和res...
    99+
    2022-11-13
  • C++智能指针使用实例分析
    这篇文章主要介绍了C++智能指针使用实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C++智能指针使用实例分析文章都会有所收获,下面我们一起来看看吧。1.简介程序运行时存在静态空间、栈和堆区,用堆来存储动...
    99+
    2023-06-30
  • C++智能指针实例代码分析
    这篇文章主要讲解了“C++智能指针实例代码分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++智能指针实例代码分析”吧!一、内存泄漏-永恒的话题动态申请堆空间,用完后不归还C++ 语言中...
    99+
    2023-06-30
  • C++的智能指针使用实例分析
    今天小编给大家分享一下C++的智能指针使用实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。什么是RAIIRAII(Re...
    99+
    2023-06-29
  • 深入学习C++智能指针之shared_ptr与右值引用的方法
    目录1. 介绍2. 初始化方法2.1 通过构造函数初始化2.2 通过拷贝和移动构造函数初始化2.3 通过 std::make_shared 初始化2.4 通过 reset 方法初始化...
    99+
    2022-11-12
  • C++深入分析讲解智能指针
    目录1.简介2.unique_ptr指针(独占指针)3.shared_ptr指针(共享所有权)4.weak_ptr(辅助作用)5.自实现初级版智能指针6.总结1.简介 程序运行时存在...
    99+
    2022-11-13
  • C++学习之移动语义与智能指针的实例分析
    这篇文章给大家分享的是有关C++学习之移动语义与智能指针的实例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。移动语义1.几个基本概念的理解(1)可以取地址的是左值,不能取地址的就是右值,右值可能存在寄存器,也...
    99+
    2023-06-15
  • 如何进行C++智能指针的实现
    本篇文章为大家展示了如何进行C++智能指针的实现,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。自己根据http://blog.csdn.net/lf_2016/article/details/524...
    99+
    2023-06-06
  • C++11智能指针unique_ptr用法使用场景分析
    一、概述 C++ 标准模板库 STL(Standard Template Library) 一共给我们提供了四种智能指针:auto_ptr、unique_ptr、shared_ptr...
    99+
    2022-11-12
  • C++之智能指针初步及弃用auto_ptr的原因分析
    目录RAIIRAII的四个步骤裸指针存在的问题智能指针智能指针的引入四种智能指针总结RAII 使用局部对象来管理资源的技术 RAII的原理 RAII的四个步骤 裸指针存在的问题...
    99+
    2023-03-23
    C++智能指针 C++ auto_ptr 智能指针
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作