C++智能指针详解

目录

一、什么是智能指针?

二、为什么需要智能指针?

三、C++ 智能指针的分类与使用

3.1 std::unique_ptr(独占所有权)

适用场景

3.2 std::shared_ptr(共享所有权) 

3.3 std::weak_ptr(弱引用)

注意事项:

总结


一、什么是智能指针?

在计算机编程中,特别是使用C++语言时,内存管理一直是一个复杂且容易出错的任务。程序员需要手动分配和释放内存,稍有不慎就可能导致内存泄漏或悬挂指针问题,这些问题不仅会影响程序的性能,还可能引发严重的错误甚至安全漏洞。

为了简化内存管理并减少这些潜在的问题,C++标准库引入了“智能指针”(Smart Pointer)。顾名思义,智能指针是一种封装了原始指针的对象,它能够自动管理指针的生命周期。这意味着程序员不需要手动分配和释放内存,智能指针会自动处理这些任务,确保资源得到合理使用。

C++标准库提供了三种主要的智能指针:

  1. std::unique_ptr:这是“独占型”的智能指针,表示它对所管理的对象拥有唯一的所有权。当unique_ptr超出作用域时,它会自动释放所管理的对象,确保不会出现悬空指针问题。

  2. std::shared_ptr:与unique_ptr不同,shared_ptr是“共享型”的智能指针,允许多个shared_ptr同时指向同一个对象。所有这些指针都会共同承担对对象的管理责任,当最后一个shared_ptr超出作用域时,它会自动释放所管理的对象。

  3. std::weak_ptr:这是“弱引用”类型的智能指针,不会参与对象的生命周期管理。它的主要用途是解决可能存在的循环引用问题,并且在被其管理的对象被其他shared_ptr释放后,它可以安全地变为无效状态而不引发错误。

二、为什么需要智能指针?

在 C++ 中,使用 newdelete 进行动态内存管理时,如果没有正确释放内存,就会导致 内存泄漏。此外,指针被释放后仍然访问会导致 悬挂指针,可能引发未定义行为。智能指针的优势包括:

  • 自动管理资源,防止手动 delete 造成的错误。

  • 减少内存泄漏,确保对象在合适的时间被释放。

  • 避免悬挂指针,防止指向已释放内存。

  • 支持引用计数,使多个对象安全共享同一资源。

三、C++ 智能指针的分类与使用

3.1 std::unique_ptr(独占所有权)

#include <iostream>
#include <memory>class Test {
public:Test() { std::cout << "Test 构造\n"; }~Test() { std::cout << "Test 析构\n"; }void show() { std::cout << "Test::show()\n"; }
};int main() {std::unique_ptr<Test> ptr1 = std::make_unique<Test>();ptr1->show();// 不能复制 unique_ptr// std::unique_ptr<Test> ptr2 = ptr1; // 编译错误// 但是可以移动std::unique_ptr<Test> ptr2 = std::move(ptr1);if (!ptr1) {std::cout << "ptr1 为空\n";}return 0;
}
适用场景
  • 适用于 独占资源 的情况,如文件句柄、数据库连接等。

  • 在 RAII(Resource Acquisition Is Initialization)模式中确保资源在作用域结束时释放。

3.2 std::shared_ptr(共享所有权) 

std::shared_ptr 允许多个智能指针共享同一对象,并使用 引用计数 来管理资源释放。

#include <iostream>
#include <memory>class Test {
public:Test() { std::cout << "Test 构造\n"; }~Test() { std::cout << "Test 析构\n"; }
};int main() {std::shared_ptr<Test> ptr1 = std::make_shared<Test>();{std::shared_ptr<Test> ptr2 = ptr1;std::cout << "ptr1.use_count() = " << ptr1.use_count() << "\n";}// 离开作用域后,ptr2 被销毁,引用计数减少std::cout << "ptr1.use_count() = " << ptr1.use_count() << "\n";return 0;
}

适用场景

  • 适用于 多个对象共享同一资源,例如 缓存、图数据结构 等。

  • 观察者模式回调函数 中,多个观察者共享同一数据。

3.3 std::weak_ptr(弱引用)

std::weak_ptr不增加引用计数shared_ptr,主要用于打破 循环引用

#include <iostream>
#include <memory>class B;class A {
public:std::shared_ptr<B> ptrB;~A() { std::cout << "A 析构\n"; }
};class B {
public:std::shared_ptr<A> ptrA;~B() { std::cout << "B 析构\n"; }
};int main() {auto a = std::make_shared<A>();auto b = std::make_shared<B>();a->ptrB = b;b->ptrA = a; // 循环引用,内存不会释放return 0;
}

解决方法:使用 std::weak_ptr 代替 shared_ptr

class B;
class A {
public:std::weak_ptr<B> ptrB;~A() { std::cout << "A 析构\n"; }
};class B {
public:std::weak_ptr<A> ptrA;~B() { std::cout << "B 析构\n"; }
};

适用场景

  • 适用于 避免循环引用,如 双向关联对象

  • 用于 缓存系统,防止对象被过早销毁。

注意事项:

小心 std::weak_ptr 使用,在使用 std::weak_ptr 时,需要 lock() 获取 shared_ptr,以确保对象仍然存在。

if (auto sp = weakPtr.lock()) {sp->show();
} else {std::cout << "对象已销毁\n";
}

总结

类型主要特点适用场景
unique_ptr独占所有权,不可复制独占资源,如文件句柄、数据库连接
shared_ptr共享所有权,引用计数共享资源,如缓存、观察者模式
weak_ptr不增加引用计数,防止循环引用防止循环引用,如双向关联对象

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

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

相关文章

罗杰斯特回归

定义 逻辑回归其实就是原来的线性回归加了激活函数&#xff0c;这个函数其实就是sigmoid函数&#xff0c;把一个回归的连续数值压缩到了0到1的空间&#xff0c;其实只要有函数能够满足把数值压缩到0,1之间就可以&#xff08;因为0到1之间的数值就是概率值&#xff09; 对于分类…

Elasticsearch 高级

Elasticsearch 高级 建议阅读顺序&#xff1a; Elasticsearch 入门Elasticsearch 搜索Elasticsearch 搜索高级Elasticsearch高级&#xff08;本文&#xff09; 1. nested 类型 1.1 介绍 Elasticsearch 中的 nested 类型允许你在文档内存储复杂的数据结构&#xff0c;比如一个…

基于SpringBoot实现的高校实验室管理平台功能四

一、前言介绍&#xff1a; 1.1 项目摘要 随着信息技术的飞速发展&#xff0c;高校实验室的管理逐渐趋向于信息化、智能化。传统的实验室管理方式存在效率低下、资源浪费等问题&#xff0c;因此&#xff0c;利用现代技术手段对实验室进行高效管理显得尤为重要。 高校实验室作为…

leetcode_704. 二分查找_java

704. 二分查找https://leetcode.cn/problems/binary-search/ 1.题目 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 示…

python基础学习三(元组及字符串的使用)

文章目录 元组什么是元组元组的创建方式为什么要将元组设计成不可变序列元组的遍历集合集合的相关操作集合操作集合的数学操作集合生成式列表&#xff0c;字典&#xff0c;元组&#xff0c;集合总结 字符串字符串的驻留机制判断字符串的操作方法字符串的比较操作字符串的切片操…

游戏被外挂攻破?金融数据遭篡改?AI反作弊系统实战方案(代码+详细步骤)

一、背景与需求分析 随着游戏行业与金融领域的数字化进程加速,作弊行为(如游戏外挂、金融数据篡改)日益复杂化。传统基于规则的防御手段已难以应对新型攻击,而AI技术通过动态行为分析、异常检测等能力,为安全领域提供了革命性解决方案。本文以游戏反作弊系统和金融数据安…

深入理解 TypeScript 中的类型断言(Type Assertion)

类型断言是 TypeScript 中一个强大而独特的特性&#xff0c;它允许开发者告诉编译器&#xff1a;"我知道这个值的类型是什么&#xff0c;请相信我"。本文将全面探讨类型断言的概念、语法、使用场景、最佳实践以及潜在陷阱&#xff0c;帮助你在 TypeScript 开发中更有…

matplotlib标题比x,y轴字体大,明明标题字体更大?

原始代码&#xff1a; plt.xlabel(训练轮次&#xff08;Epochs&#xff09;, fontsize14, fontweightbold, fontpropertieschinese_font) # 设置中文字体、加大、加粗 plt.ylabel(R值, fontsize14, fontweightbold, fontpropertieschinese_font) # 设置中文字体、加大、加粗…

MySQL DQL,数据查询语言的用法

语法&#xff1a;select 字段名 from 表名 [where <条件>]选择符合条件的记录 group by 字段名表 :分组 having <条件> :选择符合条件的组 order by 字段名表 …

Python练习之抽奖界面

前言 一、代码整体架构分析 1、数据层 (Model) 2、控制层 (Controller) 3、视图层 (View) 二、核心功能实现详解 1、 文件导入功能 1.1、实现逻辑 1.2、代码涉及知识点讲解 1.2.1、wildcard 1.2.2、wx.FileDialog 1.2.3、dlg.ShowModal() 2、抽奖动画控制 1.1、…

Vue3 项目通过 docxtemplater 插件动态渲染 .docx 文档(带图片)预览,并导出

Vue3 项目通过 docxtemplater 插件动态渲染 .docx 文档&#xff08;带图片&#xff09;预览&#xff0c;并导出 预览安装插件示例代码项目目录结构截图实际效果截图 动态渲染 .docx 文档&#xff08;带图片&#xff09;&#xff0c;预览、导出安装插件docx 模板文件内容完整代码…

springmvc redirect 使用https后跳转到了http://域名:443问题处理

最近在处理一个很久之前的项目的时候&#xff0c;由于需要将http升级到https&#xff0c;导致springmvc项目中配置的redirect报错 线上的返回结果是http://abc.test.com:443/jrbac/mobile/wechat.html 通过nginx配置了一下解决了&#xff0c;记录一下 location /jrbac {proxy…

用空闲时间做了一个小程序-二维码生成器

一直在摸鱼中赚钱的大家好呀~ 先向各位鱼友们汇报一下情况&#xff0c;目前小程序已经有900的鱼友注册使用过。虽然每天都有新的鱼友注册&#xff0c;但是鱼友增长的还很缓慢。自从国庆前的文字转语音的工具上线到现在已经将近有1个月没有更新小程序了。但是今天终终终终终于又…

【JavaEE】springMVC返回Http响应

目录 一、返回页面二、Controller和ResponseBody与RestController区别三、返回HTML代码⽚段四、返回JSON五、HttpServletResponse设置状态码六、设置Header6.1 HttpServletResponse设置6.2 RequestMapping设置 一、返回页面 步骤如下&#xff1a; 我们先要在static目录下创建…

【新手初学】SQL注入getshell

一、引入 木马介绍&#xff1a; 木马其实就是一段程序&#xff0c;这个程序运行到目标主机上时&#xff0c;主要可以对目标进行远程控制、盗取信息等功能&#xff0c;一般不会破坏目标主机&#xff0c;当然&#xff0c;这也看黑客是否想要搞破坏。 木马类型&#xff1a; 按照功…

验证Linux多进程时间片切换的程序

​​ 一、软件需求 在同时运行多个CPU密集型进程时&#xff0c;需采集以下统计信息&#xff1a; 当前运行在逻辑CPU上的进程ID每个进程的运行进度百分比 实验程序设计要求&#xff1a; 1. 命令行参数 参数说明示例值n并发进程数量3total总运行时长&#xff08;毫秒&…

Spring笔记03-依赖注入

简述: Spring 依赖注入&#xff08;Dependency Injection&#xff0c;DI&#xff09;是 Spring 框架的核心功能之一&#xff0c;它通过将对象的依赖关系交由 Spring 容器来管理&#xff0c;实现了对象之间的解耦&#xff0c;提高了代码的可维护性和可测试性。 构造器注入示例:…

减少采样空间方法 变成后验概率

又 因为后验概率很难计算 --所以通过引入变分分布来近似 后验概率分布 同时 引入 kl散度来度量 近似的效果好不好 什么是kl散度 kl散度带变分&#xff1a; 第一个问题 &#xff1a;积分变期望 问题二&#xff1a;贝叶斯公式 第三个问题&#xff1a;为啥可以独立出来 因为相比…

【keil】单步调试

一、步骤 1、打开stc-isp软件 2.打开keil仿真设置&#xff0c;选择对应的单片机型号 3.点击将所选目标单片机设置为仿真芯片&#xff0c;点击下载&#xff0c;按一下单片机打下载按钮 4.此时已经将仿真程序下载到单片机 5.此时点击options,找到debug选择STC Montor 51 Driv…

【即插即用涨点模块-卷积】SPDConv空间深度卷积,助力小目标与低分辨有效涨点【附源码+注释】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…