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

面试手撕------智能指针

通常在面试中需要手撕实现的是shared_ptr,其主要特性是使用一个计数器进行对资源的管理。在面试中只需要简单要实现的以下功能:

  1. 引用计数:通过计数器跟踪指针被引用的次数
  2. 自动内存管理:当引用计数归零时自动释放内存
  3. 拷贝语义:支持深拷贝,增加引用计数
  4. 移动语义:支持资源所有权的转移
  5. 异常安全:移动操作使用noexcept保证安全性
  6. 操作符重载:支持常规指针的*和->操作

1、成员变量

也就是说在其中需要两个成员变量,一个是需要存储的指针,另一个是一个计数器。

那么计数器的类型是什么?

首先,该指向同一个资源的计数器值需要相同,可以同步对计数器的增加或减少。截至到这时有两种方式

1、指针

2、static。

那么他们有什么区别?static在泛型编程中每一个类型都共享这个变量,而同一个类型不一定只有一个资源。所以static不可行。也就是说是这样的

template <typename T>
class  SmartPoint
{
private:
	T* prt;
	size_t* count;
};

2、计数器减少

由于拷贝构造和析构函数都有可能对计数器经行减少删除,所以将这一步封装成一个新的函数(记得是私有函数)。

void release() {
		if(--(*count) == 0)
		{
			delete ptr;
			delete count;
			ptr = nullptr;
			count == nullptr;
			std::cout << "资源已经释放" << std::endl;
		}
	}

3、构造函数、析构函数

通常在智能指针构造函数中,我们都是传入一个new出来的指针交由智能指针管理或是不传参。且我们不希望指针在传入时出现隐式类型转换,所以使用explicit关键字

	explicit SmartPoint(T* p = nullptr) :ptr(p),count(new size_t(1))
	{
		std::cout << "创建智能指针" << endl;
	}
	~SmartPoint()
	{
		if (count)release();
	}

4、拷贝构造函数、拷贝赋值运算符

在这两个中要注意的就是为了防止两个成员变量发生改变要使用const,以及拷贝赋值运算符需要返回*this(见Effective C++条款10:令operator=返回一个reference to *this)和this在拷贝赋值前需要先删除原先资源。

	SmartPoint(const SmartPoint<T>& other)
		:ptr(other.ptr), count(other.count)
	{
		++(*count);
		std::cout << "拷贝构造智能指针" << (*count) << std::endl;
	}
	SmartPoint<T>& operator=(const SmartPoint<T>& other)
	{
		if (this != &other)
		{
			release();
			ptr = other.ptr;
			count = other.count;
			++(*count);
			std::cout << "拷贝赋值,计数" << *count << std::endl;
		}
		return *this;
	}

5、移动拷贝构造函数、移动拷贝赋值运算符

移动拷贝是对资源的直接移动,不会让计数器发生增加或者减少,因为传入的是右值,只需要将资源转移就行。

要注意的是容器重新分配时,使用移动而不是拷贝,前提是移动操作是noexcept的,否则会回退到拷贝,影响性能。

SmartPoint(SmartPoint<T>&& other) noexcept
		:ptr(other.ptr), count(other.count)
	{
		other.ptr = nullptr;
		other.count = nullptr;

	}
	SmartPoint<T>& operator=(SmartPoint<T>&& other) noexcept 
	{
		if (this != &other)
		{
			release();
			ptr = other.ptr;
			count = other.count;
			other.ptr = nullptr;
			other.count = nullptr;
		}
		return *this;
	}

6、重载操作符

T& operator*() const { return *ptr; }
	T* operator->() const { return ptr; }
	size_t use_count() const { return count ? *count : 0; }

7、测试

// 示例使用
int main() {
	SmartPoint<int> p1(new int(42));  // 计数 1
	{
		SmartPoint<int> p2 = p1;      // 拷贝构造,计数 2
		SmartPoint<int> p3;
		p3 = p2;                        // 拷贝赋值,计数 3
		std::cout << "数值: " << *p3 << "\n";
	}                                   // p2/p3 析构,计数 1
	SmartPoint<int> p4 = std::move(p1); // 移动构造
	std::cout << "移动后计数: " << p4.use_count() << "\n";
	return 0;
}

请添加图片描述

http://www.dtcms.com/a/112232.html

相关文章:

  • 操作系统、虚拟化技术与云原生及云原生AI简述
  • JavaScript智能对话机器人——企业知识库自动化
  • 使用HTML5和CSS3实现炫酷的3D立方体动画
  • 地球科学领域常用python库
  • 软件工程面试题(十九)
  • Redis高级技能进阶
  • 【GPT写代码】动作视频切截图研究器
  • MATLAB中plot函数的详细参数表
  • 数据结构:二叉树(三)·(重点)
  • 医疗信息系统的主要痛点分析
  • session临时文件包含
  • 【教学类-102-02】自制剪纸图案(留白边、沿线剪)02——Python+PS自动化添加虚线边框
  • ROS订阅相机图像识别颜色并发布识别信息
  • 【进收藏夹吃灰】Python基础学习指南
  • 【读书笔记·VLSI电路设计方法解密】问题61:扫描插入的目的是什么
  • java 局部内部类
  • Git 教程:从 0 到 1 全面指南 教程【全文三万字保姆级详细讲解】
  • DPDI版本升级说明
  • AI提示词:分享卡片生成器
  • 浅析 Spring AI 与 Python:企业级 AI 开发的技术分野
  • 在Git中如何处理冲突?
  • 目前主流OCR/语义理解/ASR
  • 使用mcp自定义编写mcp tool,使用 conda 启动,在cline中配置使用
  • MOM成功实施分享(八)汽车活塞生产制造MOM建设方案(第一部分)
  • fastGPT—前端开发获取api密钥调用机器人对话接口(HTML实现)
  • GIt 分布式版本控制系统
  • ND4J的MemoryWorkspace
  • [2018][note]用于超快偏振开关和动态光束分裂的all-optical有源THz超表——
  • 【FPGA基础学习】状态机思想实现流水灯
  • 推理模型与普通大模型如何选择?