从0开始C++(十一):智能指针

目录

概念

作用

auto_ptr(自动指针)

 unique_ptr(唯一指针)

 shared_ptr(共享指针)

weak_ptr(虚指针)

补充:手写一个共享指针类


概念

C++的智能指针是一种用于管理动态分配内存的指针。它是C++语言的一个重要特性,通过自动管理内存资源,帮助开发人员避免内存泄漏和悬空指针的问题。

智能指针的作用是在动态分配内存时提供更方便、更安全的管理方式,使开发人员无需手动释放内存。它们可以跟踪对象的生命周期,并在不再需要时自动释放内存,大大减少了内存泄漏的可能性。

作用

智能指针有以下几个主要作用:

  1. 自动释放内存:智能指针使用了RAII(资源获取即初始化)的原则,即在初始化时获取资源,在对象销毁时自动释放资源。这样可以确保在离开作用域时,分配的内存会被正确释放。

  2. 简化内存管理:智能指针隐藏了手动释放内存的细节,减少了开发人员的工作量和出错的机会。开发人员无需记住所有动态分配内存的位置,也无需手动调用delete释放内存。

  3. 避免悬空指针问题:悬空指针是指指向已释放内存的指针,使用悬空指针可能导致未定义行为或程序崩溃。智能指针通过在对象不再使用时自动释放内存,有效地避免了悬空指针问题。

  4. 解决资源泄漏问题:使用智能指针,资源的释放与其生命周期绑定,确保资源在不再需要时被正确释放。这可以帮助避免资源泄漏,如忘记释放内存、文件句柄或其他系统资源。

总之,C++的智能指针在动态内存管理方面发挥了重要作用,提供了更安全、更方便的内存管理方式。通过使用智能指针,可以减少内存泄漏和悬空指针问题,提高代码的可靠性和可维护性。

 C++四种智能指针

● auto_ptr(自动指针)C++98 已废弃)

● unique_ptr(唯一指针)C++11)

● shared_ptr(共享指针)C++11)

● weak_ptr(虚指针)C++11)

使用智能指针需要引入对应头文件 #include<memory> 

auto_ptr(自动指针)

auto_ptr是C++98标准中提供的一种智能指针,用于管理动态分配的对象。它的使用方式如下:

1、创建auto_ptr对象:

可以使用auto_ptr模板类创建auto_ptr对象。

auto_ptr<T> ptr(new T);

其中,T是所要管理对象的类型,new T会动态分配内存并返回指向这个新对象的指针。

2、使用auto_ptr对象:

ptr.get()->MemberFunction(); //取出被管理的堆内存对象,并调用成员函数

3、所有权转移:

auto_ptr的一个特点是所有权转移,当将一个auto_ptr赋值给另一个auto_ptr时,原来的auto_ptr将不再管理对象。

auto_ptr<T> ptr1(new T); // 创建auto_ptr对象ptr1
auto_ptr<T> ptr2; // 创建auto_ptr对象ptr2ptr2 = ptr1; // 所有权从ptr1转移到ptr2,ptr1不再管理对象

需要注意的是,一旦所有权转移,原来的auto_ptr将变为空指针,并且不应再对其进行解引用或操作。

4、离开作用域的自动销毁:

当auto_ptr对象超出其作用域时,它所管理的对象将会被自动删除。

{auto_ptr<T> ptr(new T); // 在作用域内创建auto_ptr对象// 使用ptr对象
} // 在作用域结束时,ptr对象会被销毁,所管理的对象也会被自动释放

auto_ptr的析构函数会调用delete操作符来释放对象内存,因此不适用于管理动态分配的数组和其他类型的资源。

总而言之,auto_ptr的使用方式包括创建auto_ptr对象、使用auto_ptr对象、所有权转移和离开作用域自动销毁。但由于其存在一些问题,建议使用C++11及以上版本提供的更安全和更强大的智能指针类型,如unique_ptr和shared_ptr。

 unique_ptr(唯一指针)

unique_ptr是C++11引入的一种智能指针,用于管理动态分配的对象。与auto_ptr相比,unique_ptr具有更安全和更强大的功能。它的使用方式和auto_ptr几乎一样,只有权限转移时操作有所区别。

使用move函数来进行所有权转移。

unique_ptr<T> ptr1(new T); // 创建unique_ptr对象ptr1
unique_ptr<T> ptr2; // 创建unique_ptr对象ptr2ptr2 = move(ptr1); // 所有权从ptr1转移到ptr2,ptr1不再管理对象

unique_ptr提供了更安全和更灵活的资源管理功能,是C++中推荐使用的智能指针类型之一。

 

shared_ptr(共享指针)

shared_ptr是C++11引入的一种智能指针,用于管理动态分配的对象。不同于unique_ptr,shared_ptr允许多个指针共享同一个对象,并且会跟踪对象的引用计数。当引用计数为0时,对象会被自动删除。以下是shared_ptr的使用方式:

1、创建shared_ptr对象: 可以使用shared_ptr模板类创建shared_ptr对象。

shared_ptr<T> ptr(new T);

其中,T是所要管理对象的类型,new T会动态分配内存并返回指向这个新对象的指针。

2、使用shared_ptr对象: 

ptr.get()->MemberFunction(); //取出被管理的堆内存对象,并调用成员函数

3、共享所有权:

shared_ptr的最大特点是可以共享所有权,即多个shared_ptr对象可以指向同一个对象。当最后一个指向对象的shared_ptr被销毁时,对象才会被自动删除。

shared_ptr<T> ptr1(new T); // 创建shared_ptr对象ptr1
shared_ptr<T> ptr2 = ptr1; // ptr2也指向ptr1所管理的对象// 使用ptr1和ptr2对象

4、获取引用计数: 可以使用 shared_ptr 的 use_count() 函数获取当前共享对象的引用计数。

int count = ptr.use_count(); // 获取ptr对象所管理对象的引用计数

5、离开作用域的自动销毁: 当最后一个指向对象的shared_ptr离开其作用域时,对象将会被自动删除

{std::shared_ptr<T> ptr(new T); // 在作用域内创建shared_ptr对象// 使用ptr对象
} // 在作用域结束时,ptr对象会被销毁,如果没有其他shared_ptr指向对象,则对象也会被自动释放

 

weak_ptr(虚指针)

weak_ptr是C++11引入的一种智能指针,用于解决循环引用的问题。与shared_ptr不同,weak_ptr是一种弱引用,它不会增加对象的引用计数,也不会拥有对象的所有权。以下是weak_ptr的使用方式:

1、创建weak_ptr对象: 可以使用weak_ptr模板类创建weak_ptr对象。

std::weak_ptr<T> ptr;

2、创建weak_ptr对象并与shared_ptr对象绑定: 可以使用shared_ptr的成员函数lock()创建一个weak_ptr对象,并与一个shared_ptr对象绑定。

shared_ptr<T> sharedPtr(new T);
weak_ptr<T> weakPtr = sharedPtr;

3、使用weak_ptr对象:

使用weak_ptr对象的方式与使用shared_ptr对象相似,可以使用lock()函数获取一个shared_ptr对象,从而访问weak_ptr所指向的对象。

shared_ptr<T> sharedPtr = weakPtr.lock(); // 获取一个shared_ptr对象
if (sharedPtr) {// 使用sharedPtr对象
}

lock()函数会返回一个指向共享对象的 shared_ptr ,如果 weak_ptr 已经过期(即其所指向的对象已被释放),则lock()函数返回一个空的shared_ptr。

4、检查 weak_ptr 是否过期: 可以使用 expired() 函数检查 weak_ptr 是否过期,即其所指向的对象是否已被释放。

if (weakPtr.expired()) {// weakPtr已过期,所指对象已释放
}

5、使用weak_ptr解决循环引用: 当需要解决循环引用问题时,可以使用weak_ptr和shared_ptr组合使用。其中,有一个shared_ptr作为主要的引用,而另一个shared_ptr使用weak_ptr进行引用,这样就打破了循环引用。

#include <iostream>
#include <memory>using namespace std;class B;class A {
public:weak_ptr<B> bPtr; // 引入weak_ptr~A() {cout << "A destructor called" << endl;}
};class B {
public:weak_ptr<A> aPtr; // 引入weak_ptr~B() {cout << "B destructor called" << endl;}
};int main() {shared_ptr<A> aPtr = make_shared<A>();shared_ptr<B> bPtr = make_shared<B>();aPtr->bPtr = bPtr; // 将bPtr赋值给aPtr的weak_ptr成员bPtr->aPtr = aPtr; // 将aPtr赋值给bPtr的weak_ptr成员return 0;
}

 

补充:手写一个共享指针类

#include <iostream>
#include <memory>   // 智能指针头文件
using namespace std;template<class T>
class SharedPtr
{
private:T *res = NULL;  // 资源指针int *count = NULL;  // 引用计数public:SharedPtr(T *t):res(t),count(new int(1)){}// 拷贝构造函数SharedPtr(const SharedPtr &sp):res(sp.res),count(sp.count){(*count)++; // 计数+1}// 赋值运算符重载SharedPtr &operator =(const SharedPtr &sp){if(&sp != this){// 销毁原来的资源reset();res = sp.res;count = sp.count;(*count)++;}return *this;}void reset(){(*count)--; // 计数-1if(*count == 0){delete res;delete count;}res = NULL;count = NULL;}T* get()const{return res;}int use_count()const{return *count;}~SharedPtr(){reset();}
};class Test
{
private:string s;
public:Test(string s):s(s){cout << s << "构造函数" << endl;}~Test(){cout << s << "析构函数" << endl;}void show(){cout << s << "执行程序" << endl;}
};int main()
{SharedPtr<Test> sp1(new Test("A")); // 构造函数sp1.get()->show();cout << sp1.use_count() << endl;    // 1SharedPtr<Test> sp2(sp1); // 拷贝构造函数cout << sp2.use_count() << endl;    // 2SharedPtr<Test> sp3(new Test("B"));cout << sp3.use_count() << endl;    // 1sp3 = sp2;  // 赋值运算符重载sp3.get()->show();cout << sp3.use_count() << endl;    // 3return 0;
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/34872.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言入门系列:特殊的main函数和exit函数

文章目录 一&#xff0c;main函数二&#xff0c;exit函数1&#xff0c;exit函数2&#xff0c;atexit()函数2.1 atexit函数的简介2.2 atexit注册的函数一定会被调用吗2.2.1 正常退出测试2.2.2 异常退出测试 一&#xff0c;main函数 一个C程序至少包含一个函数&#xff0c;这个函…

机器学习Python代码实战(二)分类算法:k-最近邻

一.k-最近邻算法步骤 1.选择适当的k值。它表示在预测新的数据点时要考虑的邻居数量。 2.计算距离。计算未知点与其他所有点之间的距离。常用的距离计算方法主要有欧氏距离&#xff0c;曼哈顿距离等。 3.选择邻居。在训练集中选择与要预测的数据点距离最近的k个邻居。 4.预测…

利用浏览器DevTools中对React项目进行内存泄露排查

利用浏览器DevTools中对React项目进行内存泄露排查 场景&#xff1a;用户在某个页面操作时&#xff0c;在监控平台收集到的数据表现为内存占用有逐步提高的趋势&#xff0c;最先想到的是 DOM 元素卸载后其 JavaScript 对象未能被垃圾回收这类内存泄漏问题。同时&#xff0c;如…

解决 macOS 中“无法验证开发者”的问题

解决 macOS 中“无法验证开发者”的问题 在使用 macOS 系统时&#xff0c;你可能会遇到一个常见的问题&#xff1a;当你尝试安装或打开某些应用程序时&#xff0c;系统会弹出一个警告&#xff0c;提示“无法验证开发者”。这通常发生在从非官方 App Store 下载的应用程序上。本…

随机步问题

随机步问题 1.题目简介2.题目分析3.创建变量4.主程序5.程序效果6.程序可以改进的点 1.题目简介 2.题目分析 数组初始化 生成随机方向 判断程序结束的标志 当前元素为Z&#xff0c;或者四个方向都堵住了 3.创建变量 arry[ROW][COL]创建二维数组 _Bool a,b,c,d判断是否会出现四…

(新)Spring Security如何自定义失败处理器

&#xff08;直接从三、实战开始看&#xff09; &#xff08;直接从三、实战开始看&#xff09; &#xff08;直接从三、实战开始看&#xff09;可点击&#xff1a; &#xff08;新&#xff09;Spring Security如何自定义失败处理器-CSDN博客 我们还希望在认证失败或者是授…

ChatGPT 的原理简介

人工智能&#xff08;AI&#xff09;在过去的几十年里取得了巨大的进步&#xff0c;其中一种令人瞩目的应用就是聊天机器人。ChatGPT 就是这样一款通过自然语言处理与用户进行对话的 AI 工具。它是基于 OpenAI 的 GPT&#xff08;Generative Pre-trained Transformer&#xff0…

ESP32 双线汽车接口 (TWAI)

一&#xff1a;TWAI概述 双线汽车接口 (TWAI) 是一种适用于汽车和工业应用的实时串行通信协议。它兼容 ISO11898-1 经典帧&#xff08;CAN2.0&#xff09;&#xff0c;因此可以支持标准帧格式&#xff08;11 位 ID&#xff09;和扩展帧格式&#xff08;29 位 ID&#x…

【Qt】Qt出现“xcb”相关错误,解决方法汇总

1、缺少 libxcb 库 1.1 Ubuntu系统 1)问题 在Ubuntu等桌面系统中,第一次Qt程序时报错: qt.qpa.plugin:Could not load the Qt platform plugin “xcb“2)原因 详细原因查找步骤,参考博客:【Qt】Ubuntu18.04下解决Qt出现qt.qpa.plugin:Could not load the Qt platform …

thinksboard新建菜单

1.打开目录\thingsboard\ui-ngx\src\app\modules\home\pages新增npages文件夹 2.新增npages.module.ts以及npages-routing.module.ts控制文件&#xff0c;以及页面展示文件npages.component.html,npages.component.scss,npages.component.ts 3.打开npages.component.ts文件&…

最新AI智能聊天对话问答系统源码(详细图文搭建部署教程)+AI绘画系统,DALL-E3文生图, Whisper TTS 语音识别,文档分析

一、人工智能 随着人工智能技术的持续进步&#xff0c;AI绘画已经发展成为一个日益成熟的领域。越来越多的人开始尝试使用AI绘画软件来创作艺术作品。尽管这些AI绘画软件对绘画领域产生了显著影响&#xff0c;但它们并不会完全取代画师。与传统手绘不同&#xff0c;AI绘画可以…

【第2章】MyBatis-Plus代码生成器

文章目录 前言一、安装二、生成方式1.DefaultQuery (元数据查询)2.存在问题 三、快速生成1. 生成代码2. 目录结构 四、交互式总结 前言 全新的 MyBatis-Plus 代码生成器&#xff0c;通过 builder 模式可以快速生成你想要的代码&#xff0c;快速且优雅&#xff0c;跟随下面的代…

Pikachu 靶场 SSRF 通关解析

前言 Pikachu靶场是一种常见的网络安全训练平台&#xff0c;用于模拟真实世界中的网络攻击和防御场景。它提供了一系列的实验室环境&#xff0c;供安全专业人士、学生和爱好者练习和测试他们的技能。 Pikachu靶场的目的是帮助用户了解和掌握网络攻击的原理和技术&#xff0c;…

揭秘软文发稿秘诀:打造高效推广营销

你是否有在看一篇文章时&#xff0c;可能明知道它是一则广告但仍心甘情愿的继续了解下去&#xff0c;这样的文章大概率就是一篇软文&#xff0c;在当今信息爆炸的时代&#xff0c;软文作为一种有效的推广营销手段&#xff0c;已经成为各大企业、品牌争相使用的利器。然而&#…

安装Cmakeffmpeglibssh

首先安装cmake&#xff1a; sudo apt install cmake cmake --version然后这个输出正常就装好了 然后安装ffmpeg: tar xvzf n4.4.tar.gz cd FFmpeg-n4.4 chmod x configure ./configure --enable-gpl --enable-nonfree --enable-libx264 --enable-debug --disable-opti…

关于VMware遇到的一些问题

问题一&#xff1a;打不开磁盘…或它所依赖的某个快照磁盘&#xff0c;开启模块DiskEarly的操作失败&#xff0c;未能启动虚拟机 解决方法&#xff1a; 首先将centos 7关机&#xff0c;然后把快照1删掉 然后打开虚拟机所在目录&#xff0c;把提示的000001.vmdk全部删除&…

Java创建一个线程发生的事情

Java创建一个线程发生的事情 1.分配线程栈 线程对象被创建后&#xff0c;JVM会分配一个独立的线程栈&#xff0c;用于存储该线程的方法调用、局部变量等。还有本地方法栈&#xff0c;用来调用本地方法栈服务。还有程序计数器&#xff0c;这个就是我们线程所执行字节码指示灯&…

Spring Boot中的自定义Starter开发

Spring Boot中的自定义Starter开发 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们来探讨如何在Spring Boot中开发一个自定义Starter&#xff0c;以便在…

Linux:系统引导过程与服务控制

目录 一、linux 系统引导过程 1.1、引导过程总览 1.2、系统初始化进程 &#xff08;centos 6和7 的区别&#xff09; 1.2.1、centos 6 的引导过程 init 进程 1.2.2、centos 7(systemd进程) 二、MBR、GRUB菜单、忘记密码故障修复 2.1、修复MBR扇区故障 模拟故障 重启…

详解 ClickHouse 的表引擎

一、简介 表引擎决定了如何存储表的数据。包括&#xff1a; 数据的存储方式和位置&#xff0c;写到哪里以及从哪里读取数据支持哪些查询以及如何支持并发数据访问索引的使用&#xff08;如果存在&#xff09;是否可以执行多线程请求数据复制参数 表引擎的使用方式&#xff1a;…