C++智能指针的实现

ops/2024/11/1 9:50:35/

本篇文章详细探讨下如何使用裸指针实现智能指针。

补充内容

由于本篇文章主要是探讨怎么实现三种智能指针,但是在编码过程中,博主可能会使用些有些同学不了解的特性,为了保证大家思绪不被打断,博主先把这些小特性介绍出来,大家选择性参考。

1、什么是RAII?

RAII(Resource Acquisition Is Initialization)是一种资源管理技术,常用于 C++ 编程中。其核心理念是将资源的获取和释放与对象的生命周期绑定在一起。这样,资源的管理(如内存、文件句柄、网络连接等)可以通过对象的构造和析构来自动化,确保资源不会泄漏。

RAII 的基本原则

  1. 资源获取:

    当一个对象被创建时(即构造函数被调用),它会获取所需的资源。这可以是动态分配的内存、打开的文件、网络连接等。

  2. 资源释放

    当对象的生命周期结束时(即析构函数被调用),它会自动释放所获取的资源。这意味着无论是正常退出还是由于异常退出,资源都会得到正确释放。

2、noexcept是什么

用noexcept声明函数表示此函数不会抛出异常。编译器在处理这样的函数时,就不会进行不必要的异常安全处理,从而提高性能。并且,noexcept可以确保函数在发生错误(异常)时,会直接终止程序,不会进入异常处理模块,确保程序不会进入未被定义的状态。

例如如下代码

虽然func内部抛出异常后,程序会直接调用std::terminate()结束运行,而不会进入catch程序块。

void func() noexcept {throw std::runtime_error("This will terminate the program");
}int main() {try {func();} catch (...) {// 不会被执行}return 0;
}

3、声明函数的末尾的=delete是什么作用

1、=delete:函数声明时,末尾添加=delete表示此函数被禁用,通常用于禁用复制构造函数、赋值运算符等特定函数。使用方法如下

class MyClass {
public:// 拷贝构造函数被删除MyClass(const MyClass&) = delete;// 拷贝赋值运算符被删除MyClass& operator=(const MyClass&) = delete;
}

4、转换运算符

在 C++ 中,转换运算符是一种特殊的成员函数,用于将类的对象转换为其他类型的对象。它允许你定义如何将自定义类型转换为内置类型或其他用户定义类型。

转换运算符将在发生显式类型转换和隐式类型转换时被调用。

class MyClass {
private:int __data = 0;
public:MyClass(double v) : __data(v) {}operator int() {cout << "operator int called" << endl;return __data;}operator double() {cout << "operator double called" << endl;return static_cast<double>(__data);}operator bool(){cout << "operator bool called" << endl;return __data != 0;}
};int main() {MyClass obj(10); // 正确!显式转换,调用MyClass(int)构造函数if(obj) // 发生隐式类型转换,operator bool被调用{int a = obj; // 发生隐式类型转换,operator int被调用double b = static_cast<double>(obj); //发生显式类型转换,operator int被调用}return 0;
}

方案

1、首先,定义一个模板类,即使用泛型编程,使得该类可以管理各种类别;

2、其次,需要根据各个智能指针的特点重载运算符:*(解引用)、->(指向)、[]、= 等使得这个类能方便的进行和指针的操作;

3、实现智能指针的常用函数;

4、最重要的,是在类中实现好内存管理。

智能指针是使用了RAII技术用于实现资源的管理。

实现

一、unique_ptr

unique_ptr是一种独占所有权的智能指针,表示一个指针只能被一个unique_ptr所有,不能被复制,只能被移动。所以,我们在实现unique_ptr的时候,除了上诉整体方案,需要注意将其的拷贝构造函数禁用。

具体实现

1、构造函数

1) 在类内管理一个传入数据类型的指针;

2) 在构造时候开辟内存或者赋值,并在析构函数中释放,实现RAII技术;

3) 因为是独占资源的指针,需要将拷贝构造函数禁用;

4)允许移动构造函数,将传入对象的资源接管过来,同时注意释放传入对象对资源的控制(将__ptr置nullptr)

template<typename T>
class unique_ptr{
private:

http://www.ppmy.cn/ops/130101.html

相关文章

AI实践-PyTorch-CNN-手写数字识别

1 需求 2 接口 3 示例 4 参考资料 PyTorch——手写数字识别_pytorch 手写数字-CSDN博客 Python &#xff1a;MNIST手写数据集识别 手写板程序 最详细&#xff0c;直接放心&#xff0c;大胆地抄&#xff01;跑不通找我&#xff0c;我包教&#xff01;_手写数字数据集-CSDN博客…

蓝桥杯基本操作和运算

文章目录 1.基本运算2.循环--进制转换/最大公约数2.1进制转换2.2求解最大公约数 3.数组与字符串4.常用的API5.快速读写模版 蓝桥杯基本操作和运算 10-22号正式开始准备蓝桥杯的比赛&#xff0c;准备参加这个大学B组的Java的赛项 1.基本运算 首先就是基本的输入输出&#xff1…

论文翻译 | PROMPTAGATOR : FEW-SHOT DENSE RETRIEVAL FROM 8 EXAMPLES

摘要 最近的信息检索研究主要集中在如何从一个任务&#xff08;通常有丰富的监督数据&#xff09;转移到其他各种监督有限的任务上&#xff0c;其隐含的假设是从一个任务可以泛化到所有其他任务。然而&#xff0c;这忽略了这样一个事实&#xff0c;即存在许多多样化和独特的检索…

redis详细教程(2.List教程)

List是一种可以存储多个有序字符串的数据类型&#xff0c;其中的元素按照顺序排列&#xff08;可以重复出现&#xff09;&#xff0c;可以通过数字索引来访问列表中的元素&#xff0c;索引可以从左到右或者从右到左。 Redis 列表可以通过两种方式实现&#xff1a;压缩列表&…

HCIA(ACL)

第七节 ACL&#xff1a;访问控制列表 访问控制----在路由器的入或者出的接口上&#xff0c;匹配流量&#xff0c;之后产生动作---允许或拒绝 定义感兴趣流量-----帮助其他软件抓流量 匹配规则&#xff1a; 至上而下&#xff0c;逐一匹配&#xff0c;上调匹配按照上条执行…

能通过Ping命令访问CentOS 9 Stream,但在使用Xshell连接

能通过Ping命令访问CentOS 9 Stream&#xff0c;但在使用Xshell进行SSH连接失败 1. **确认SSH服务状态**&#xff1a;2. **检查SSH配置**&#xff1a;要检查和设置PermitRootLogin选项&#xff0c;您需要编辑SSH配置文件/etc/ssh/sshd_config。以下是具体步骤&#xff1a;1. 打…

VUE3——readonly与shallowReadonly

1. readonly 用于创建一个ref或者reactive定义的响应式数据的深只读副本。 0.1 用法&#xff1a; const sum reactive(0); const readOnlyCopy readonly(sum); readOnlyCopy console.log(readOnlyCopy); // 输出 00.2 特点&#xff1a; 对象的所有嵌套属性都将变为只读&…

fetch 与 xmlHttpRequest 请求总结

文章目录 fetch 、XMLHttpRequest、ajax 简要介绍fetch 与 xmlHttpRequest 比较 fetch 、XMLHttpRequest、ajax 简要介绍 Fetch API 概述 Fetch是一种现代的JavaScript API&#xff0c;用于在浏览器中进行网络请求。它提供了一种更灵活、更强大的方式来获取资源&#xff0c;相…