当前位置: 首页 > article >正文

[模拟实现]unique_ptr、shared_ptr智能指针--C++版本的代码实现

一、unique_ptr

        unique_ptr是在auto_ptr的基础之上,解决了多个智能指针同时指向一个对象,发生管理权转移,只有一个智能指针指向了对象,其他的都是管理的空对象的行为。这里的多个智能指针指向同一个对象是通过拷贝构造或者赋值重载实现的,unique_ptr的解决办法就是将这两种方式禁用掉,不让其进行这类操作,保证了同一时间只有一个智能指针指向该对象。

1.构造函数与析构函数

    std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>(1);
    std::unique_ptr<MyClass> ptr2(new MyClass(1));

        上述的是C++标准库的版本,第一个属于标准库提供的函数,用来在堆上创建一个MyClass对象,并将该对象传递给智能指针,两个其实都是调用的构造函数。所以构造函数的实现就很简单,将这个申请的堆空间的地址,传递给该智能指针内部的变量即可。

        析构函数也能简单,智能指针的作用就是用于将申请到的空间的存在周期和智能指针对象的生命周期进行绑定,所以智能指针释放的时候,就需要释放堆空间了。

2.移动构造和移动拷贝

        不可以使用拷贝构造和赋值重载是因为使用之后,会产生智能指针管理空对象,如果在使用该智能指针的话,就会出现问题了,但是对于将亡值这类,就不存在了,这类对象的管理权转移给别人之后他们也就销毁了。所以不存在管理空对象的智能指针问题。

3. 其他函数

        还要实现的是指针的相关操作,如*和->的运算符重载函数,还要获取该管理对象的函数get函数。

4.代码实现与测试
#include <iostream>

// 测试代码
class MyClass 
{
public:
	MyClass() { std::cout << "MyClass constructor" << std::endl; }
	~MyClass() { std::cout << "MyClass destructor" << std::endl; }
	void doSomething() { std::cout << "Doing something..." << std::endl; }
};

namespace ns_ptr
{
	template<class T>
	class unique_ptr
	{
	private:
		T* _ptr;

		// 禁用拷贝构造和赋值重载
		unique_ptr(const unique_ptr&) = delete;
		unique_ptr& operator=(const unique_ptr&) = delete;

	public:
		// 构造函数
		unique_ptr(T* space) :_ptr(space){}
		// 析构函数
		~unique_ptr() { if (_ptr != nullptr) delete _ptr; }

		// 移动拷贝和移动赋值
		unique_ptr(unique_ptr&& other)
			: _ptr(other._ptr)
		{
			other._ptr = nullptr;
		}
		unique_ptr& operator=(unique_ptr&& other)
		{
			if(this != &other)
			{
				// 释放旧对象
				delete _ptr;
				// 管理新对象
				_ptr = other._ptr;
				other._ptr = nullptr;
			}
		}

		// 指针的相关操作
		T& operator*() { return *_ptr; }
		T* operator->() { return _ptr; }

		//获取该指针对象
		T* get() { return _ptr; }
	};
}


int main() 
{
	ns_ptr::unique_ptr<MyClass> ptr1(new MyClass());
	ptr1->doSomething();

	// 转移所有权
	ns_ptr::unique_ptr<MyClass> ptr2 = std::move(ptr1);
	if (!ptr1.get()) {
		std::cout << "ptr1 is empty after move" << std::endl;
	}
	(*ptr2).doSomething();

	return 0;
}

二、shared_ptr

        shared_ptr允许同一时间有多个智能指针同时指向同一个对象,并在内部维护一个引用计数,记录有多少个智能指针指向这个对象。那么这个智能指针就不需要禁用拷贝构造和赋值重载函数了。这里的引用计数必须实时的在每一个智能指针内部更新,所以我们需要将引用计数单独提取出来,而不是有一个新的智能指针就去挨个更改其他智能指针内部的引用计数的值。所以这里单独设计了一个引用计数类。

1.构造函数与析构函数

        shared_ptr类内部有两个变量,一个是指针,另一个是引用计数类对象。当初始化的时候,会创建一个引用计数类,并初始化值为1。析构该对象的时候,会将引用计数减一,然后去判断引用计数是否为0了,如果为0的话,就可以进行析构管理的空间了。

2.拷贝构造和赋值重载函数

        他俩类似,都是将other内部的两个对象进行值拷贝,然后将引用计数加一即可,赋值重载额外需要对管理的就对象考虑是否要析构。

3. 其他函数

        还要实现的是指针的相关操作,如*和->的运算符重载函数,还要获取该管理对象的函数get函数与获取引用计数值的函数。

4.代码实现与测试
#include<iostream>

namespace ns_ptr
{
	// 引用计数类
	template<class T>
	class ref_count
	{
	private:
		int _count;
	public:
		// 构造函数与析构函数
		ref_count() : _count(1) {}
		~ref_count() {}

		// 引用计数的增减
		void addCount() { ++_count; }
		int delCount() { return --_count; }
		// 获取引用计数
		int getCount() { return _count; }
	};

	// 智能指针类
	template<class T>
	class shared_ptr
	{
	private:
		ref_count<T>* _ref;   // 引用计数类
		T* _ptr;

	public:
		// 构造函数与析构函数
		shared_ptr(T* space) 
			: _ptr(space)
			, _ref(new ref_count<T>())
		{}
		~shared_ptr()
		{
			// 减少引用计数
			_ref->delCount();
			// 获取引用计数
			if (_ref->getCount() == 0)
			{
				delete _ptr;
				delete _ref;
			}
		}

		// 拷贝构造和赋值重载函数
		shared_ptr(const shared_ptr& other)
			: _ptr(other._ptr)
			, _ref(other._ref)
		{
			// 增加引用计数
			_ref->addCount();
		}
		shared_ptr& operator=(const shared_ptr& other)
		{
			if (this != &other)
			{
				// 引用计数减少1,如果为0了,就析构旧对象
				if (_ref->delCount() == 0)
				{
					delete _ptr;
					delete _ref;
				}
				_ref = other._ref;
				_ref->addCount();
				_ptr = other._ptr;
			}
			return *this;
		}

		// 解引用相关运算符
		T& operator*() { return *_ptr; }
		T* operator->() { return _ptr; }
		// 获取引用计数
		int use_count() { return _ref->getCount(); }
	};
}

// 测试代码
class MyClass {
public:
	MyClass() { std::cout << "MyClass constructor" << std::endl; }
	~MyClass() { std::cout << "MyClass destructor" << std::endl; }
	void doSomething() { std::cout << "Doing something..." << std::endl; }
};

int main() {
	// 创建一个 MySharedPtr 对象
	ns_ptr::shared_ptr<MyClass> ptr1(new MyClass());
	std::cout << "ptr1 use count: " << ptr1.use_count() << std::endl;

	// 拷贝构造
	ns_ptr::shared_ptr<MyClass> ptr2(ptr1);
	std::cout << "ptr1 use count: " << ptr1.use_count() << std::endl;
	std::cout << "ptr2 use count: " << ptr2.use_count() << std::endl;

	// 赋值操作
	ns_ptr::shared_ptr<MyClass> ptr3(ptr2);
	ptr3 = ptr1;
	std::cout << "ptr1 use count: " << ptr1.use_count() << std::endl;
	std::cout << "ptr2 use count: " << ptr2.use_count() << std::endl;
	std::cout << "ptr3 use count: " << ptr3.use_count() << std::endl;

	// 调用成员函数
	ptr1->doSomething();

	return 0;
}


http://www.kler.cn/a/590823.html

相关文章:

  • 【自学笔记】MongoDB基础知识点总览-持续更新
  • 一条SQL在mysql数据库中经历的过程
  • STM32——基本定时器
  • 相机光学(四十七)——相纸材质
  • 神经网络量化3-全连接层实现量化
  • 相机标定之DLT算法学习
  • 对话傅盛:AI时代的超级应用是什么?
  • 【Python】10、集合
  • 使用fastapi部署stable diffusion模型
  • 3D点云目标检测——KITTI数据集读取与处理
  • 完全托管的DeepSeek-R1模型正式登陆Amazon Bedrock:安全部署与使用指南
  • Java的继承:方法;属性?
  • 个人学习编程(3-18) leetcode刷题
  • 在云平台上用Claude 3.7 AI代理自动化电脑图形界面点击操作做表格
  • PostgreSQL17允许psql的\watch在返回最小行数后停止
  • 2025年3月19日 十二生肖 今日运势
  • 电子硬件入门(三)——偏置电路
  • 模型评估——acc、P、R、F值、交叉验证、K折交叉验证
  • PATB1113 钱串子的加法
  • C++ 友元 / friend关键字解读