C++ 共享智能指针

介绍

前面我们介绍了,智能指针以及唯一性智能指针,这一节介绍共享智能指针,共享智能指针与唯一性智能指针不同,它可以通过拷贝构造进行赋值,并且全部都属于浅拷贝,即所有指针指向的内存是共享的

具体可以参考这一篇博客 链接: link.

共享指针的实现

在这里插入图片描述

#pragma once
using namespace std;
template<class _Ty>
class MyDeletor //可接受一切类型方案
{
public:
	MyDeletor() = default;//默认构造函数
	void operator()(_Ty* ptr) const
	{
		if (ptr != nullptr)
		{
			delete ptr;
		}
	}
};
template<class _Ty>
class MyDeletor<_Ty[]> //部分特化
{
public:
	MyDeletor() = default;
	void operator()(_Ty* ptr)const
	{
		if (ptr != nullptr)
		{
			delete[] ptr;
		}
	}
};

template<class _Ty>
class RefCnt
{
public:
	_Ty* mptr;
	int ref; //多线程下会不安全,需要加上原子操作
	//#include<atomic>
	//std::atomic_int ref;
public:
	RefCnt(_Ty* p = nullptr) :mptr(p), ref(mptr != nullptr)
	{}
	~RefCnt()
	{}
};

template<class _Ty, class _Dx = MyDeletor<_Ty>>
class my_shared_ptr
{
public:
	my_shared_ptr(_Ty* p = nullptr) :ptr(nullptr)
	{
		if (p != nullptr)
		{
			ptr = new RefCnt<_Ty>(p);
		}
	}
	my_shared_ptr(const my_shared_ptr& _src) :ptr(_src.ptr)
	{
		if (ptr != nullptr)
		{
			ptr->ref++;
		}
	}
	my_shared_ptr(my_shared_ptr&& _src) :ptr(_src.ptr)
	{
		_src.ptr = nullptr;
	}
	operator bool() const
	{
		return ptr != nullptr;
	}
	my_shared_ptr& operator=(const my_shared_ptr& _Y)
	{
		if (&_Y == this || ptr == _Y.ptr)//防止指向同一个值
		{
			return *this;
		}
		if (ptr != NULL && --ptr->ref == 0)
		{
			mDeletor(ptr);
		}
		ptr = _Y.ptr;
		if (ptr != nullptr)
		{
			ptr->ref++;
		}
		return *this;

	}
	my_shared_ptr& operator=(my_shared_ptr&& _Y)
	{
		if (&_Y == this)
		{
			return *this;
		}
		if (this->ptr == _Y.ptr && this->ptr != nullptr)
		{
			this->ptr->ref--;
			_Y.ptr = nullptr;
			return *this;
		}
		if (ptr != nullptr && --ptr->ref == 0)
		{
			mDeletor(ptr->mptr);
			delete ptr;
		}
		ptr = _Y.ptr;
		_Y.ptr == nullptr;
		return *this;
	}
	void reset(_Ty* p = nullptr)
	{
		if (this->ptr != nullptr && --this->ptr->ref == 0)
		{
			mDeletor(ptr->mptr); //抛弃旧的引用计数
			delete ptr;
		}
		ptr = new RefCnt<_Ty>(p);//获得新的引用计数
	}
	~my_shared_ptr()
	{
		if (this->ptr != nullptr && --this->ptr->ref == 0)
		{
			mDeletor(ptr->mptr);
			delete ptr;
		}
		ptr = nullptr;
	}
	_Ty* get()const
	{
		return ptr->mptr;
	}
	_Ty& operator*() const
	{
		return *get();
	}
	_Ty* operator->()const
	{
		return get();
	}
	size_t use_count() const
	{
		if (this->ptr == nullptr)
		{
			return 0;
		}
		return this->ptr->ref;
	}
	void swap(my_shared_ptr& r)
	{
		std::swap(this->ptr, r.ptr);
	}

private:
	RefCnt<_Ty>* ptr;
	_Dx  mDeletor;
};

template<class _Ty, class _Dx>
class my_shared_ptr<_Ty[], _Dx>
{
public:
	my_shared_ptr(_Ty* p = nullptr) :ptr(nullptr)
	{
		if (p != nullptr)
		{
			ptr = new RefCnt<_Ty>(p);
		}
	}
	my_shared_ptr(const my_shared_ptr& _src) :ptr(_src.ptr)
	{
		if (ptr != nullptr)
		{
			ptr->ref++;
		}
	}
	my_shared_ptr(my_shared_ptr&& _src) :ptr(_src.ptr)
	{
		_src.ptr = nullptr;
	}
	operator bool() const
	{
		return ptr != nullptr;
	}
	my_shared_ptr& operator=(const my_shared_ptr& _Y)
	{
		if (&_Y == this || ptr == _Y.ptr)//防止指向同一个值
		{
			return *this;
		}
		if (ptr != NULL && --ptr->ref == 0)
		{
			mDeletor(ptr);
		}
		ptr = _Y.ptr;
		if (ptr != nullptr)
		{
			ptr->ref++;
		}
		return *this;

	}
	my_shared_ptr& operator=(my_shared_ptr&& _Y)
	{
		if (&_Y == this)
		{
			return *this;
		}
		if (this->ptr == _Y.ptr && this->ptr != nullptr)
		{
			this->ptr->ref--;
			_Y.ptr = nullptr;
			return *this;
		}
		if (ptr != nullptr && --ptr->ref == 0)
		{
			mDeletor(ptr->mptr);
			delete ptr;
		}
		ptr = _Y.ptr;
		_Y.ptr == nullptr;
		return *this;
	}
	void reset(_Ty* p = nullptr)
	{
		if (this->ptr != nullptr && --this->ptr->ref == 0)
		{
			mDeletor(ptr->mptr); //抛弃旧的引用计数
			delete ptr;
		}
		ptr = new RefCnt<_Ty>(p);//获得新的引用计数
	}
	~my_shared_ptr()
	{
		if (this->ptr != nullptr && --this->ptr->ref == 0)
		{
			mDeletor(ptr->mptr);
		}
		ptr = nullptr;
	}
	_Ty* get()const
	{
		return ptr->mptr;
	}
	_Ty& operator*() const
	{
		return *get();
	}
	_Ty* operator->()const
	{
		return get();
	}
	size_t use_count() const
	{
		if (this->ptr == nullptr)
		{
			return 0;
		}
		return this->ptr->ref;
	}
	void swap(my_shared_ptr& r)
	{
		std::swap(this->ptr, r.ptr);
	}
	_Ty& operator[](const int idx)const
	{
		return ptr->mptr[idx];
	}


private:
	RefCnt<_Ty>* ptr;
	_Dx  mDeletor;
};

智能指针的两种创建方式

std::shared_ptr<Object> op1(new Object(10));
std::shared_ptr<Obejct> op2 = std::make_shared<Object>(20);

这样两种不同的智能指针构建方式,其内存结构是不同的

对于第一种方式来说,op1有一个ptr指针和一个删除器(mDeletor),ptr指针指向引用计数对象(RefCnt),引用计数对象有mptr指针和引用计数(ref),mptr直指向Object对象,Object对象的value域的值为10,在这个过程中在堆区的构建new了两次,分别是创建引用计数对象与Object对象

对于第二种方式来说进行了一些的优化,它能够计算出Object的大小和引用计数对象的大小,直接一次开辟够Object对象和引用计数大小一样的空间,引用计数对象的mptr指针指向Object对象,在这个过程中在堆区的构建只new一次
在这里插入图片描述

  • make_shared 最大的好处就是减少单次内存分配的次数,这几乎就是我们使用make_shared的唯一理由
  • 另一个好处就是可以增大Cache局部性:使用make_shared,计数器的内存和原生内存就在堆上排排坐,这样的话我们所有要访问的两个内存的操作就会比另一种方案减少一半的cache misses

引入Cache的理论基础是程序局部性原理,包括时间局部性和空间局部性;即最近被CPU访问的数据,短期内CPU还要访问(时间);被CPU访问的数据附近的数据,CPU短期内还要访问(空间);因此如果刚刚访问过的数据缓存在Cache中,那下次访问时,可以直接从Cache中取,其速度可以得到数量级的提高,CPU要访问的数据在Cache中有缓存,称为“命中”(Hit),反之称为“缺失”(Miss)

循环引用

class Child;
class Parent
{
public:
	shared_ptr<Child> child;
	Parent() { cout << "Parent" << endl; }
	~Parent() { cout << "~Parent" << endl; }
	void hi() { cout << "Hello" << endl; }
};
class Child
{
public:
	shared_ptr<Parent> parent;
	Child() { cout << "Child" << endl; }
	~Child() { cout << "~Child" << endl; }
};
void fun()
{
	shared_ptr<Parent> p = make_shared<Parent>();
	shared_ptr<Child> c = make_shared<Child>();

	p->child = c;
	c->parent = p;
	c->parent->hi();
}
int main()
{
	fun();
	return 0;
}

在这里插入图片描述
此时两个智能指针的引用计数都为2,但是当函数生命周期结束,引用计数结果为1,那么会出现只有构造函数没有析构函数
在这里插入图片描述
这里就需要引入弱引用智能指针

class Child;
class Parent
{
public:
	//shared_ptr<Child> child;
	std::weak_ptr<Child> child;
	Parent() { cout << "Parent" << endl; }
	~Parent() { cout << "~Parent" << endl; }
	void hi() { cout << "Hello" << endl; }
};
class Child
{
public:
	//shared_ptr<Parent> parent;
	std::weak_ptr<Parent> parent;
	Child() { cout << "Child" << endl; }
	~Child() { cout << "~Child" << endl; }
};
void fun()
{
	shared_ptr<Parent> p = make_shared<Parent>();
	shared_ptr<Child> c = make_shared<Child>();

	p->child = c;
	c->parent = p;
	//c->parent->hi();
}
int main()
{
	fun();
	return 0;
}

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值