C++ 中的智能指针与内存管理:从基础到进阶
在 C++ 中,内存管理是一个至关重要的课题,尤其是当程序复杂度逐渐增加时。传统的手动内存管理方式(使用 new
和 delete
)容易引发内存泄漏、悬挂指针等问题。为了简化内存管理,C++11 引入了智能指针(std::unique_ptr
、std::shared_ptr
和 std::weak_ptr
),它们通过自动化内存管理,帮助开发者减少了很多潜在的错误。本文将深入探讨 C++ 中智能指针的使用、原理以及最佳实践。
一、什么是智能指针?
智能指针是一种封装了原生指针的类,通过管理内存的生命周期,自动释放资源。智能指针主要有以下几种:
std::unique_ptr
:独占所有权的智能指针,只有一个unique_ptr
可以指向某个资源,且资源在unique_ptr
销毁时自动释放。std::shared_ptr
:共享所有权的智能指针,多个shared_ptr
可以共享对同一资源的控制权,直到最后一个shared_ptr
被销毁,资源才会被释放。std::weak_ptr
:弱引用智能指针,不增加引用计数,避免shared_ptr
的循环引用问题。
二、std::unique_ptr
:独占所有权
std::unique_ptr
是最简单的智能指针,它只允许一个指针指向一个资源,并在生命周期结束时自动销毁资源。这种设计能够有效避免资源泄漏,并且不需要手动释放内存。
示例:使用 std::unique_ptr
#include <iostream>
#include <memory>class Resource {
public:Resource() { std::cout << "Resource acquired\n"; }~Resource() { std::cout << "Resource destroyed\n"; }
};int main() {// 使用 make_unique 创建 unique_ptrstd::unique_ptr<Resource> res = std::make_unique<Resource>();// unique_ptr 超出作用域时,自动释放内存return 0;
}
输出:
Resource acquired
Resource destroyed
在这个示例中,std::make_unique
用于创建 std::unique_ptr
,它会在程序结束时自动释放资源。unique_ptr
的所有权不能被复制,因此它是独占的。我们不能把 unique_ptr
赋值给另一个 unique_ptr
,但可以通过 std::move
转移所有权。
三、std::shared_ptr
:共享所有权
std::shared_ptr
是一种共享所有权的智能指针。多个 shared_ptr
可以指向同一个资源,并且通过引用计数来管理资源的生命周期。当最后一个 shared_ptr
被销毁时,资源才会被释放。
示例:使用 std::shared_ptr
#include <iostream>
#include <memory>class Resource {
public:Resource() { std::cout << "Resource acquired\n"; }~Resource() { std::cout << "Resource destroyed\n"; }
};int main() {std::shared_ptr<Resource> res1 = std::make_shared<Resource>();std::shared_ptr<Resource> res2 = res1; // 共享所有权std::cout << "Shared pointers count: " << res1.use_count() << std::endl;// 当 res1 和 res2 超出作用域时,资源会被自动释放return 0;
}
输出:
Resource acquired
Shared pointers count: 2
Resource destroyed
在这个示例中,res1
和 res2
都指向同一个 Resource
对象。它们共享对资源的所有权,当 res1
和 res2
都被销毁时,资源会自动释放。use_count()
方法可以查看当前有多少个 shared_ptr
指向该资源。
四、std::weak_ptr
:弱引用
std::weak_ptr
是一种不增加引用计数的智能指针,它通常与 std::shared_ptr
配合使用,用于解决 shared_ptr
的循环引用问题。当两个 shared_ptr
相互引用时,资源会永远不能被释放,导致内存泄漏。std::weak_ptr
通过不增加引用计数来打破这种循环。
示例:使用 std::weak_ptr
解决循环引用
#include <iostream>
#include <memory>class Node {
public:std::shared_ptr<Node> next;std::weak_ptr<Node> prev; // 使用 weak_ptr 避免循环引用~Node() { std::cout << "Node destroyed\n"; }
};int main() {auto node1 = std::make_shared<Node>();auto node2 = std::make_shared<Node>();node1->next = node2;node2->prev = node1; // 使用 weak_ptr 来避免循环引用return 0; // 节点会被自动销毁
}
输出:
Node destroyed
Node destroyed
在这个示例中,node1
和 node2
形成了一个双向链表。prev
成员使用 std::weak_ptr
,这样就避免了 shared_ptr
的循环引用。当 node1
和 node2
超出作用域时,资源会被正确释放。
五、智能指针的内存管理原理
智能指针的内存管理基于 引用计数 和 RAII(资源获取即初始化)原则:
- 引用计数:
std::shared_ptr
内部维护一个引用计数,表示有多少个shared_ptr
正在共享这个资源。当引用计数为 0 时,资源会被销毁。 - RAII 原则:智能指针通过构造和析构函数管理资源的生命周期。当智能指针创建时,它自动获取资源;当智能指针超出作用域时,它会自动释放资源。
简化实现:std::shared_ptr
的引用计数
#include <iostream>template <typename T>
class SimpleSharedPtr {
private:T* ptr;int* refCount;public:explicit SimpleSharedPtr(T* p = nullptr) : ptr(p), refCount(new int(1)) {}SimpleSharedPtr(const SimpleSharedPtr& other) : ptr(other.ptr), refCount(other.refCount) {++(*refCount);}~SimpleSharedPtr() {--(*refCount);if (*refCount == 0) {delete ptr;delete refCount;}}T& operator*() { return *ptr; }T* operator->() { return ptr; }
};
六、最佳实践与注意事项
- 避免裸指针和智能指针混用:如果一个资源已经由智能指针管理,就不应再使用裸指针去访问它。
- 避免循环引用:
std::shared_ptr
在引用计数的情况下,如果两个对象互相持有shared_ptr
,会导致资源永远无法释放。使用std::weak_ptr
来打破循环引用。 - 尽量使用
std::make_unique
和std::make_shared
:这两个函数可以更安全、简洁地创建智能指针,避免裸指针带来的风险。
七、总结
智能指针是现代 C++ 编程的重要工具,能够大大简化内存管理,并帮助开发者避免内存泄漏和悬挂指针等问题。通过 std::unique_ptr
、std::shared_ptr
和 std::weak_ptr
的合理使用,C++ 程序员可以更高效地管理资源,提升代码的健壮性和可维护性。
掌握智能指针的使用和内部原理,你将能够编写出更加安全、优雅的 C++ 代码。如果有任何问题或心得,欢迎在评论区分享!
相关文章:
C++ 中的智能指针与内存管理:从基础到进阶
在 C 中,内存管理是一个至关重要的课题,尤其是当程序复杂度逐渐增加时。传统的手动内存管理方式(使用 new 和 delete)容易引发内存泄漏、悬挂指针等问题。为了简化内存管理,C11 引入了智能指针(std::unique…...
二、使用langchain搭建RAG:金融问答机器人--数据清洗和切片
选择金融领域的专业文档作为源文件 这里选择 《博金大模型挑战赛-金融千问14b数据集》,这个数据集包含若干公司的年报,我们将利用这个年报搭建金融问答机器人。 具体下载地址 这里 git clone https://www.modelscope.cn/datasets/BJQW14B/bs_challenge_…...
R 语言 | 绘图的文字格式(绘制上标、下标、斜体、文字标注等)
1. 上下标 # 注意y轴标签文字 library(ggplot2) ggplot(mtcars, aes(mpg, cyl))geom_point()ylab(label bquote(O[3]~(ug / m^3)))2. 希腊字母,如alpha ggplot(mtcars, aes(mpg, cyl))geom_point()ylab(label bquote(O[3]~(ug / m^3)))ggtitle(expression(alpha))…...
版本更新导致前端网站资源加载失败:Failed to fetch dynamically imported module
前端网站在维护过程中经常有版本更新和重新部署,而这会导致一些问题,其中某些问题会导致更新时,正在网站中的用户无法正常使用。 异常 Failed to fetch dynamically imported module 的诱发原因之一就是版本更新:在用户访问网站的…...
CentOS 7 安装、测试和部署FastDFS
目录 FastDFS环境搭建 安装 libfastcommon 库 安装FastDFS 查看编译后的文件 FastDFS配置 FastDFS启动 启动tracker服务 启动storage服务 查看storage是否已经注册到了tracker下 查看存储文件的目录 FastDFS重启 FastDFS关闭 使用fdfs_test进行测试 修改client.co…...
elasticache备份
Elasticsearch 本地快照操作流程 配置快照存储路径 在 elasticsearch.yml 文件中配置以下字段以指定数据、日志和快照存储路径:path:data: /data/data # 数据存储路径logs: /data/log # 日志存储路径repo: /data/snapshot # 快照存储路径确保路径 /dat…...
wordpress调用指定分类ID下 相同标签的内容
要在WordPress中调用分类ID为1、3、7的分类下,具有相同标签的前10个内容,可以使用自定义的WordPress查询(WP_Query)。以下是实现此功能的步骤和示例代码: 步骤: 确定共同标签: 首先,你需要确定分类1、3、…...
Spring Security 6 系列之五 - 授权管理
之所以想写这一系列,是因为之前工作过程中使用Spring Security,但当时基于spring-boot 2.3.x,其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0,结果一看Spring Security也升级为6.3.0,关键是其风…...
贪心算法求解跳跃游戏
跳跃游戏1: 代码随想录链接:代码随想录 思路: 求解是否能够跳到数组的最后一个位置,关键在于跳跃的覆盖范围 因此设置一个变量表示每次移动时能够覆盖的范围,该变量的初始值为0 因为坐标的位置受到覆盖范围的限制,因此只能遍历覆盖范围内…...
4大应用场景揭秘:AI视频监控在养老院中的智能化管理与安全保障
随着人口老龄化的加剧,养老院的管理面临着越来越多的挑战。传统的人工巡查方式不仅难以做到全天候监控,而且存在响应迟缓、效率低下等问题。为了解决这些问题,AI视频监控系统,利用人工智能技术提供了一种高效、智能化的解决方案。…...
构建简洁之美:我的第一个前端页面
实现界面效果 1. HTML示例代码 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><link rel"stylesheet…...
重拾设计模式--备忘录模式
文章目录 备忘录模式(Memento Pattern)概述定义: 作用:实现状态的保存与恢复支持撤销 / 恢复操作 备忘录模式UML图备忘录模式的结构原发器(Originator):备忘录(Memento)&…...
联通光猫怎么自己改桥接模式?
环境: 联通光猫 ZXHN F677V9 硬件版本号 V9.0 软件版本号 V9.0.0P1T3 问题描述: 联通光猫怎么自己改桥接模式 家里用的是ZXHN F677V9 光猫,最近又搞了个软路由,想改桥接模式 解决方案: 1.拿到最新超级密码&…...
UITableView实现通讯录效果
// // TableViewIndexViewController.m // study2024 // // Created by figo zhu on 2024/12/22. //#import "TableViewIndexViewController.h" //实现协议UITableViewDelegate,UITableViewDataSource interface TableViewIndexViewController ()<UITableView…...
Pytorch | 利用NI-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击
Pytorch | 利用NI-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击 CIFAR数据集NI-FGSM介绍背景算法流程 NI-FGSM代码实现NI-FGSM算法实现攻击效果 代码汇总nifgsm.pytrain.pyadvtest.py 之前已经针对CIFAR10训练了多种分类器: Pytorch | 从零构建AlexNet对CIFAR10进行…...
【Matlab】绘制混淆矩阵示意图+colormap调整方法
主代码 %https://blog.csdn.net/weixin_42943114/article/details/81811556 %https://blog.csdn.net/Mark711/article/details/141144280 clc clear close all warning off %% 原始数据 % 假设groundTruth和predictions是已经定义好的向量 TrueLabels [1 2 1 3 2 3 1 3 2 1 4…...
计算机视觉目标检测——DETR(End-to-End Object Detection with Transformers)
计算机视觉目标检测——DETR(End-to-End Object Detection with Transformers) 文章目录 计算机视觉目标检测——DETR(End-to-End Object Detection with Transformers)摘要Abstract一、DETR算法1. 摘要(Abstract)2. 引言(Introduction&#…...
资源型数字化平台该如何顺利运营?
一、引言 随着信息技术的迅猛发展,资源型数字化平台在各领域的重要性日益凸显。此类平台整合各类资源,以数字化手段提升资源利用效率与价值,但确保其顺利运营面临诸多挑战。 二、资源型数字化平台特点 资源型数字化平台具有资源整合性&…...
写SQL太麻烦?免费搭建 Text2SQL 应用,智能写 SQL | OceanBase AI 实践
自OceanBase 4.3.3版本推出以来,向量检索的能力受到了很多客户的关注,也纷纷表达希望OB能拓展更多 多模数据库大模型 的AI应用实践。 在上篇文章 👉 OceanBase LLM,免费构建你的专属 AI 助手 ,我们介绍了如何去搭建一…...
Linux系统编程——系统内核中的信号
目录 一、前言 二、系统内核中的信号 三、sigset_t 四、信号集操作 1、sigpending(); 2、sigemptyset(); 3、sigfillset(sigset_t *set); 4、int sigaddset ()和sigdelset() 编辑 5、sigismember() 6、sigprocmask() 五、信号集操作代码演示 六、深入理解进程的信…...
Mapbox-GL 中 `token` 的使用
Mapbox-GL 是一个开源的 JavaScript 库,允许开发者在网页上渲染交互式地图。token 在 Mapbox 中主要是指 access token,它用于身份验证和授权,确保应用程序能够访问 Mapbox 的地图服务。 下面详细解析 Mapbox GL 中 token 的使用,…...
PostgreSQL标识符长度限制不能超过63字节
文章目录 问题:标识符太长会被截断分析相关源码可以尝试以下案例 问题:标识符太长会被截断 在创建表时,发现表名太长会自动被截断,导致查询表时报错了。 分析 参考:https://www.postgresql.org/docs/current/limits…...
【Token】校验、会话技术、登录请求、拦截器【期末实训】实战项目学生和班级管理系统\Day15-后端Web实战(登录认证)\讲义
登录认证 在前面的课程中,我们已经实现了部门管理、员工管理的基本功能,但是大家会发现,我们并没有登录,就直接访问到了Tlias智能学习辅助系统的后台。 这是不安全的,所以我们今天的主题就是登录认证。 最终我们要实现…...
电机相关内容
文章目录 电枢电阻电动机电动势系数负载转矩直流电动机的角速度和速度关系 电枢电阻 电枢电阻的计算公式如下: 基于欧姆定律的公式: R a V a − V b I a R_a \frac{V_a - V_b}{I_a} RaIaVa−Vb 其中, ( V a ) (V_a) (Va…...
电商环境下的财务ERP系统架构
先介绍一下自己的工作经历,2002年开始进入ERP实施行业,专注于O记EBS系统,正好赶上中国经济和信息化高度发展的阶段,先后实施过很多大国企和民企的大型ERP项目,在实施过程中逐渐对ERP系统的架构、模块设计有更深入的认识…...
Gitlab 数据备份全攻略:命令、方法与注意事项
文章目录 1、备份命令2、备份目录名称说明3、手工备份配置文件3.1 备份配置文件3.2 备份ssh文件 4、备份注意事项4.1 停止puma和sicdekiq组件4.2 copy策略需要更多磁盘空间 5、数据备份方法5.1 docker命令备份5.2 kubectl命令备份5.3 参数说明5.4、选择性备份5.5、非tar备份5.6…...
基于单片机的视力保护及身姿矫正器设计(论文+源码)
1. 系统设计 在本次设计中,其系统整个框图如图2-1所示。其主要的核心控制模块由超声波模块,光敏电阻,按键模块,复位电路,红外模块,LCD显示等组成。其包括自动模式,手动模式。自动模式ÿ…...
设计模式之【观察者模式】
观察者模式: 应用于发布-订阅消息模型中,订阅者订阅一个主题后,当有新消息到达时,所有订阅者都会收到通知。 主要关注的是对象之间的通信。是一种对象之间的一对多关系,多个对象依赖于一个对象,当被依赖的…...
杂七杂八的网络安全知识
一、信息安全概述 1.信息与信息安全 信息与信息技术 信息奠基人:香农:信息是用来消除随机不确定性的东西 信息的定义:信息是有意义的数据,是一种要适当保护的资产。数据经过加工处理之后,就成为信息。而信息需要经…...
【落羽的落羽 C语言篇】数据存储简介
文章目录 一、整型提升1. 概念2. 规则 二、大小端字节序1. 概念2. 练习练习1练习2 三、浮点数在内存中的存储1. 规则2. 练习 一、整型提升 1. 概念 C语言中,整型算术运算至少是以“缺省整型类型”(int)的精度来进行的。为了达到这个精度&am…...
linux----文件访问(c语言)
linux文件访问相关函数 打开文件函数 - open 函数原型:int open(const char *pathname, int flags, mode_t mode);参数说明: pathname:这是要打开的文件的路径名,可以是绝对路径或者相对路径。例如,"/home/user/…...
垂起固定翼无人机大面积森林草原巡检技术详解
垂起固定翼无人机大面积森林草原巡检技术是一种高效、精准的监测手段,以下是对该技术的详细解析: 一、垂起固定翼无人机技术特点 垂起固定翼无人机结合了多旋翼和固定翼无人机的优点,具备垂直起降、飞行距离长、速度快、高度高等特点。这种无…...
汽车电子零部件(15):AVM全景影像系统
概述: 使用ADAS全景监控(AVM)精确停车和操纵。这项先进技术采用多个摄像头,提供车辆周围环境的鸟瞰图。 360度全景监控系统: 360 AVM系统可以帮助驾驶员360度查看车辆周围的情况,避免发生碰撞。360 AVM系统由一个电子控制单元(ECU)和四个摄像头组成。ECU将处理四个摄…...
G口带宽服务器与1G独享带宽服务器:深度剖析其差异
在数据洪流涌动的数字化时代,服务器作为数据处理的核心,其性能表现直接关系到业务的流畅度和用户体验的优劣。随着技术的飞速发展,G口带宽服务器与1G独享带宽服务器已成为众多企业的优选方案。然而,这两者之间究竟有何细微差别&am…...
鸿蒙项目云捐助第十一讲鸿蒙App应用的捐助成功自定义对话框组件实现
在生活中,用户做了一个好事后,很多场合都会收到一份感谢。在捐助的行业也是一样的,用户捐出了一片爱心,就会收获一份温情。这里的温情是通过自定义对话框实现的。 一、通过自定义对话框组件实现捐款成功的信息页 这里用户捐款成…...
Elasticsearch-分词器详解
什么是分词器 1、分词器介绍 对文本进行分析处理的一种手段,基本处理逻辑为按照预先制定的分词规则,把原始文档分割成若干更小粒度的词项,粒度大小取决于分词器规则。 常用的中文分词器有ik按照切词的粒度粗细又分为:ik_max_word和ik_smart&…...
Android笔试面试题AI答之Android基础(3)
文章目录 1.谈一谈 Android 的安全机制一、系统架构层面的安全设计二、核心安全机制三、其他安全机制与措施 2.Android 的四大组件是哪四大?3.Android 的四大组件都需要在清单文件中注册吗?4.介绍几个常用的Linux命令一、文件和目录管理二、用户和权限管…...
酷黑金色配色 影片素材不过时 色彩丰富 电影主题html
本套大作业共计8个HTML页面,网页中包含:DIVCSS、下拉菜单栏、banner轮播图、图片放大效果、鼠标滑过效果、视频、小图标及按钮设计、登录注册页等,同时设计了logo;本作品花费大量时间去整理素材,大部分素材均使用Photo…...
《Go 语言变量》
《Go 语言变量》 介绍 Go 语言是一种静态类型、编译型的编程语言,由 Google 开发。它以其简洁的语法、高效的并发处理和强大的标准库而闻名。在 Go 语言中,变量是存储数据的基本单位,它们可以是各种数据类型,如整数、浮点数、布…...
Tool之Excalidraw:Excalidraw(开源的虚拟手绘风格白板)的简介、安装和使用方法、艾米莉应用之详细攻略
Tool之Excalidraw:Excalidraw(开源的虚拟手绘风格白板)的简介、安装和使用方法、艾米莉应用之详细攻略 目录 Excalidraw 简介 1、Excalidraw 的主要特点: Excalidraw 安装和使用方法 1、Excalidraw的安装 T1、使用 npm 安装: T2、使用 …...
Llama 3 模型系列解析(一)
目录 1. 引言 1.1 Llama 3 的简介 1.2 性能评估 1.3 开源计划 1.4 多模态扩展 ps 1. 缩放法则 2. 超额训练(Over-training) 3. 计算训练预算 4. 如何逐步估算和确定最优模型? 2. 概述 2.1 Llama 3 语言模型开发两个主要阶段 2.2…...
重拾设计模式--观察者模式
文章目录 观察者模式(Observer Pattern)概述观察者模式UML图作用:实现对象间的解耦支持一对多的依赖关系易于维护和扩展 观察者模式的结构抽象主题(Subject):具体主题(Concrete Subject…...
3-Gin 渲染 --[Gin 框架入门精讲与实战案例]
在 Gin 框架中,渲染指的是将数据传递给模板,并生成 HTML 或其他格式的响应内容。Gin 支持多种类型的渲染,包括 String HTML、JSON、XML 等。 String 渲染 在 Gin 框架中,String 渲染方法允许你直接返回一个字符串作为 HTTP 响应…...
回溯---java---黑马
回溯 概念 程序在运行过程中分成了多个阶段 通过某些手段,将数据恢复到某一阶段,称之为回溯 手段包括:方法栈、自定义栈 使用基本数据类型n public class Backtracking{public static void main(String[] args) {rec(1);}public void r…...
【数据结构】排序(附测试源码)
【数据结构】排序(附测试源码) 本节是数据结构排序版(不完整版,没有C语言版的哈希表) 1.排序概念: 1.1所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增…...
【翻译】大型 Transformer 模型推理优化
翻译原文:Large Transformer Model Inference Optimization | LilLog 原文作者:Lilian Weng 目录 方法概述蒸馏 Distillation量化 Quantization Transformer 量化的挑战训练后量化 (PTQ) 混合精度量化 Mixed-precision quantization细粒度量化量化的二…...
RabbitMQ概述
目录 RabbitMQ概述 前言 MQ MQ的作用 为什么选择RabbitMQ RabbitMQ的介绍 RabbitMQ概述 前言 Rabbit, 兔⼦的意思 互联⽹⾏业很多公司, 都喜欢⽤动物命名产品, 或者作为公司的logo, 吉祥物. ⽐如: 腾讯的企鹅, 京东的狗, 美团的袋⿏, 携程的海豚,阿⾥就更多了, 蚂蚁, ⻜…...
《PCI密码卡技术规范》题目
单选1 在《PCI密码卡技术规范》中,下列哪项不属于PCI密码卡的功能()。 A.密码运算功能 B.密钥管理功能 C.物理随机数产生功能 D.随主计算机可信检测功能 正确答案:D. <font style="color:#DF2A3F;">解析:</font> 单选 2 在《PCI密码卡技术规…...
AI开发:使用支持向量机(SVM)进行文本情感分析训练 - Python
支持向量机是AI开发中最常见的一种算法。之前我们已经一起初步了解了它的概念和应用,今天我们用它来进行一次文本情感分析训练。 一、概念温习 支持向量机(SVM)是一种监督学习算法,广泛用于分类和回归问题。 它的核心思想是通过…...
ECharts柱状图-柱图42,附视频讲解与代码下载
引言: 在数据可视化的世界里,ECharts凭借其丰富的图表类型和强大的配置能力,成为了众多开发者的首选。今天,我将带大家一起实现一个柱状图图表,通过该图表我们可以直观地展示和分析数据。此外,我还将提供…...