IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 【c++智能指针】模拟实现my_shared_ptr -> 正文阅读

[C++知识库]【c++智能指针】模拟实现my_shared_ptr


在模拟my_share_ptr之前,我们深入区分一下,拷贝构造和移动构造,普通赋值和移动赋值的区别。

拷贝构造和移动构造的区别:

拷贝构造采用的方式是:将一个对象中指针所指的所有属性复制给被拷贝的对象。为了防止出现内存泄漏,需要被拷贝对象,重新申请一片堆空来存放所指之物。
移动构造是一个对象中的指针所指转移给被移动对象。因此需要将前者对他所拥有的数据的拥有权释放。

移动赋值和普通赋值的区别:

普通赋值:如 obja = base,是是将base中的指针所指赋值一份给obja。
移动就是直接转移给obja,base对资源的拥有权释放。

总结:

其实c11新引入的移动赋值和移动构造都是"右值引用"的概念的产生而产生,实际针对的是对对资源和系统内部资源进行转移引入的引入的一个新的概念。实现的是资源的转移

unique_ptr和share_ptr的区别:

unique_ptr(唯一性)智能指针,一次只能指向一个对象。
share_ptr(共享性)智能指针,多个指针可以指向同一个对象。 但是必须记录有多少个指针指向了同一个对象。

int main(void)
{
	std::shared_ptr<Object> sp1(new Object(10));

	return 0;
}

请添加图片描述当两个指针同时指向同一个对象时,那么指向的引用计数就会加一。

int main(void)
{
	std::shared_ptr<Object> sp1(new Object(10));

	std::shared_ptr<Object> sp2(sp1);

	return 0;
}

请添加图片描述
hared_ptr提供了两个函数来检查其共享的引用计数值,分别是unique()和use_count()。
use_count()函数,该函数返回当前指针的引用计数值。值得注意的是use_count()函数可能效率很低,应该只把它用于测试或调试。
unique()函数用来测试该shared_ptr是否是原始指针唯一拥有者,也就是use_count()的返回值为1时返回true,否则返回false。

std::shared_ptr<Object> sp1 = std::make_shared<Object>(10);
		std::shared_ptr<Object> sp2(new Object(10));

		cout << sp1.use_count() << endl;
		cout << sp2.unique() << endl;

请添加图片描述

sp2(new Object(10));和std::make_shared(20);的区别

 std::shared_ptr<Object> sp2(new Object(10));
                         //需要创建两个对象,一个是引用计数对象,一个是object对象
 std::shared_ptr<Object> sp1 = std::make_shared<Object>(20);
 //只创建了一次对象。

区别:

第一种,需要构建两次对象,所以就要析构两次
第二种, 只创建一次对象,只析构一次。Object完成初始化,op2直接指向既可以。
请添加图片描述

模拟my_share_ptr

删除单个对象

template<class _Ty>
class MyDeletor
{
public:
	MyDeletor() = default;
	void operator()(_Ty* ptr) const
	{
		if (ptr != nullptr)
		{
			delete ptr;
		}
	}
};

删除一组对象template

class MyDeletor<_Ty[]>
{
public:
	MyDeletor() = default;
	void operator()(_Ty* ptr) const
	{
		if (ptr != nullptr)
		{
			delete[]ptr;
		}
	}
};

引用计数类

template<typename _Ty>
class RefCnt
{
private:
	_Ty* mptr; // 指向对象的指针
	int ref;   // 引用计数 
public:
	RefCnt(_Ty* p = nullptr) : mptr(p), ref(mptr != nullptr)
	{
	}
	~RefCnt() {}
};

指向一个对象的my_share_ptr

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(p);
		}
	}
private:
	RefCnt<_Ty>* ptr;  //指向计数器的指针
	_Dx mDeletor; //删除器
};

拷贝构造:

由于是共享型智能指针,所以会让多个指针指向同一个对象,因此判断智能指针对象中ptr指针是否为空,如果不为空,对ptr->ref+1

my_share_ptr(const my_share_ptr& _Y):ptr(_Y.ptr)   //让sp2中的指针指向sp1中指针所指之物。
	{                                                  //将sp1的资源复制给sp2
		if (ptr != NULL)                              
		{
			ptr->ref += 1;
		}
	}

移动构造

  1. 移动构造相当于直接操作sp1的值(sp1被做右值),直接将sp1的值给ptr
  2. 将sp1的中指针的指向置为空。(就是将sp1的资源转移给sp2)
my_share_ptr(my_share_ptr&& _Y):ptr(_Y.ptr)  //移动构造相当于直接操作sp1的值(sp1被做右值),直接将sp1的值给ptr
{
	_Y.ptr = NULL;                        //将sp1的中指针的指向置为空。(就是将sp1的资源转移给sp2)
}

普通赋值(重点)

完成赋值需要满足的条件:

  1. if (this == &_Y || this->ptr == _Y.ptr) return *this;
my_share_ptr<Object>op1(new Object(5));
my_share_ptr<Object>op2(new Object(5));
op1 = op1;
op1 = op2;

2.if (ptr != NULL && --ptr->ref == 0)

my_share_ptr<Object>op1(new Object(5));
my_share_ptr<Object>op2(new Object(10));
op2 = op1;

请添加图片描述

  1. op1 = op2 完成,需要对ptr->ref+1,因为有两个指针同时指向op2中的指针所指的对象。
my_share_ptr& operator=(const my_share_ptr& _Y)   //将sp1中的值复制给sp2
	{
		if (this == &_Y || this->ptr == _Y.ptr) return *this;
		if (ptr != NULL && --ptr->ref == 0)
		{
			mDeletor(ptr);
		}
		ptr = _Y.ptr;
		if (ptr != nullptr)
		{
			ptr->ref += 1;
		}
		return *this;
	}
int main()
{ 
  my_share_ptr<Object>op1;
  my_share_ptr<Obbject>op2(new Object(10));
  op2 = op1;
}

请添加图片描述

int main()
{
   my_unique_ptr<Object>sp1(new Object(5));
   my_unique_ptr<Object>sp2;
   my_unique_ptr<Object>sp3;
   my_unique_ptr<Object>sp1(new Object(10));
   sp2 = sp3; //NULL = NULL
   sp2 = sp1; //NULL = 非 NULL
   sp1 = sp3; //非 NULL =  NULL
   sp2 = sp4;  //非 NULL = 非 NULL
}

两个共享性指针指向同一个对象。

请添加图片描述

移动赋值(重点)

my_share_ptr& operator =(my_share_ptr&& _Y)  //将sp1的资源转移给sp2
	{
		 //判断是否是同一个对象?
		if (this == &_Y) return *this;
		//判断各自的指针是否指向同一个对象,如果相等,在判断两个指向是否为空
		if (ptr == _Y.ptr && ptr != NULL && _Y.ptr != NULL)
		{
			ptr->ref -= 1;
			_Y.ptr = NULL;
			return *this;
		}
		//若没有指向同一个对象,判断ptr是否为空,如果不为空,并且ptr指向了一个对象
		if (ptr != NULL && --ptr->ref == 0)
		{
			MDeletor(ptr); //断开ptr对该对象的拥有权
		}
		ptr = _Y.ptr; 
		_Y.ptr = NULL;
		return *this;
	}
int main()
{
    my_unique_ptr<Object>sp1(new Object(5));
    my_unique_ptr<Object>sp3(sp1);
    my_unique_ptr<Object>sp2(sp1);
    sp1 = std::move(sp2); //采用移动构造,会将sp2移除

}

请添加图片描述

reset()函数

1.判断当前指针是否为空,并且指向一个对象。如果符合,调用删除器,解绑。
2.当前指针重新向堆区引用计数的结构,该结构的指着指向参数类的对象。

void reset(_Ty* p = nullptr)
{
	if (this->ptr != nullptr && --this->ptr->ref == 0)
	{
		mDeletor(ptr);
	}
	ptr = new RefCnt<_Ty>(p);//先调用RefCnt中的构造函数创建不具名对象,并给对mptr进行初始化,返回RefCnt的对象地址给ptr
}

析构函数

1.判断当前ptr是否为空,以及是否指向一个对象。满足条件,调用删除器,删除ptr指向的引用计数对象的mptr指针指向的对象。在删除ptr。
2.将ptr置为空。

~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);
}

指向一组对象的my_share_ptr

特点:
1.删除一组对象是,对于删除操作,我们都要先删除,当前指针所指的引用计数对象中的指针mptr所指。
2.在删除ptr指针。多个指针指向一组对象。
改下如下:

if (ptr != nullptr && --ptr->ref == 0)
{
	mDeletor(ptr->mptr);
	delete ptr;
}

提供索引访问:

_Ty& operator[](const int idx) const
{
	return ptr->mptr[idx];
}

完整代码

template<class _Ty>
class MyDeletor
{
public:
	//MyDeletor() = default;
	MyDeletor() {}
	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;
	//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 // thread;
{
public:
	my_shared_ptr(_Ty* p = nullptr) :ptr(nullptr)
	{
		if (p != nullptr)
		{
			ptr = new RefCnt(p);
		}
	}
	my_shared_ptr(const my_shared_ptr& _Y) :ptr(_Y.ptr)
	{
		if (ptr != nullptr)
		{
			ptr->ref += 1;
		}
	}// my_shared_ptr<Object> op2(op1);
	my_shared_ptr(my_shared_ptr&& _Y) :ptr(_Y.ptr)
	{
		_Y.ptr = nullptr;
	}// my_shared_ptr<Object> op2(std::move(op1));
	operator bool() const { return ptr != nullptr; }

	my_shared_ptr& operator=(const my_shared_ptr& _Y) // 
	{
		if (this == &_Y || this->ptr == _Y.ptr) return *this;
		if (ptr != NULL && --ptr->ref == 0)
		{
			mDeletor(ptr);
		}
		ptr = _Y.ptr;
		if (ptr != nullptr)
		{
			ptr->ref += 1;
		}
		return *this;
	}
	my_shared_ptr& operator=(my_shared_ptr&& _Y) // move operator =
	{
		if (this == &_Y) return *this;
		if (this->ptr == _Y.ptr && this->ptr != nullptr && _Y.ptr != nullptr)
		{
			this->ptr->ref -= 1;
			_Y.ptr = nullptr;
			return *this;
		}
		if (this->ptr != nullptr && --ptr->ref == 0)
		{
			mDeletor(ptr);
		}
		ptr = _Y.ptr;
		_Y.ptr = nullptr;
		return *this;
	}
	void reset(_Ty* p = nullptr)
	{
		if (this->ptr != nullptr && --this->ptr->ref == 0)
		{
			mDeletor(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(p);
		}
	}
	my_shared_ptr(const my_shared_ptr& _Y) :ptr(_Y.ptr)
	{
		if (ptr != nullptr)
		{
			ptr->ref += 1;
		}
	}// my_shared_ptr<Object> op2(op1);
	my_shared_ptr(my_shared_ptr&& _Y) :ptr(_Y.ptr)
	{
		_Y.ptr = nullptr;
	}// my_shared_ptr<Object> op2(std::move(op1));
	operator bool() const { return ptr != nullptr; }

	my_shared_ptr& operator=(const my_shared_ptr& _Y) // 
	{
		if (this == &_Y || this->ptr == _Y.ptr) return *this;
		if (ptr != NULL && --ptr->ref == 0)
		{
			mDeletor(ptr->mptr);
			delete ptr;
		}
		ptr = _Y.ptr;
		if (ptr != nullptr)
		{
			ptr->ref += 1;
		}
		return *this;
	}
	my_shared_ptr& operator=(my_shared_ptr&& _Y) // move operator =
	{
		if (this == &_Y) return *this;
		if (this->ptr == _Y.ptr && this->ptr != nullptr && _Y.ptr != nullptr)
		{
			this->ptr->ref -= 1;
			_Y.ptr = nullptr;
			return *this;
		}
		if (this->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);
	}

	_Ty& operator[](const int idx) const
	{
		return ptr->mptr[idx];
	}

private:
	RefCnt<_Ty>* ptr;
	_Dx mDeletor;
};
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-11-05 00:06:35  更:2022-11-05 00:11:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 3:30:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码