《编程通识》之内存安全
文章目录一、表达式值类别Value CategoriesC11起1.1 分类体系1.2 亡值(xvalue)四类标准产生场景1.3 引用绑定规则1.4 浅拷贝、深拷贝值类别与拷贝行为基础1.5 值类别控制移动构造触发二、移动语义、拷贝消除 三/五/零法则2.1 移动语义2.2 拷贝消除 Copy Elision2.3 三五零法则三、RAII 与资源所有权模型3.1 RAII 资源获取即初始化3.2 三种所有权模型3.3 weak_ptr配合shared_ptr3.4 接口设计通过类型显式表达所有权四、内存编码工程规范知识点链路表达式值类别 → 引用绑定/拷贝移动 → 拷贝消除 → 三五零资源管理准则 → RAII 所有权模型 → 工程内存编码规范✅参考学习网址https://cppreference.cn/w/一、表达式值类别Value CategoriesC11起1.1 分类体系三大基础类别左值lvalue、纯右值prvalue、亡值xvalue复合分类泛左值 g l v a l u e l v a l u e x v a l u e \mathbf{泛左值glvalue lvalue xvalue}泛左值glvaluelvaluexvalue右值 r v a l u e p r v a l u e x v a l u e \mathbf{右值rvalue prvalue xvalue}右值rvalueprvaluexvalue说明标准无“纯左值”术语工程口语指代不含亡值的普通左值正式文档禁用。类别核心特征代码示例左值 lvalue拥有持久内存地址对象生命周期较长int a 10; a数组名返回T函数调用亡值 xvalue泛左值、属于右值资源允许被转移对象即将失效std::move(a)调用返回T的函数纯右值 prvalue临时对象无持久存储没有可供转移的长期资源12std::string(hello)字面临时对象1.2 亡值(xvalue)四类标准产生场景std::move(obj)将左值强制转为亡值底层等价static_castT(obj)std::forwardT(obj)完美转发产生右值引用表达式亡值调用返回类型为右值引用 T的函数对亡值进行成员访问std::move(s).size()1.3 引用绑定规则std::string str{test};std::stringlrefstr;// ✅ T 绑定左值// std::string lref2 std::string{};// ❌ T 不能绑定纯右值conststd::stringclrefstd::string{};// ✅ const T万能绑定左值/亡值/纯右值std::stringrrefstd::move(str);// ✅ T绑定亡值// std::string rref2 str; // ❌ T不能绑定普通左值T仅绑定左值const T可绑定所有值类别T非模板仅绑定右值prvalue/xvalue模板中T为转发引用依据实参值类别自动推导左/右值引用1.4 浅拷贝、深拷贝值类别与拷贝行为基础浅拷贝仅复制指针变量多个对象指向同一块堆内存风险双重析构释放内存structBadBuffer{char*buf;BadBuffer(constchar*src){bufnewchar[strlen(src)1];strcpy(buf,src);}// 编译器默认拷贝构造 浅拷贝~BadBuffer(){delete[]buf;}};voiddemo(){BadBuffera(123);BadBuffer ba;// 浅拷贝a.buf与b.buf指向同一堆内存// 函数退出时a、b析构重复delete[] buf → 崩溃}深拷贝新建堆内存独立复制数据每个对象独占资源structDeepBuffer{char*buf;DeepBuffer(constchar*src){bufnewchar[strlen(src)1];strcpy(buf,src);}// 拷贝构造深拷贝DeepBuffer(constDeepBufferother){bufnewchar[strlen(other.buf)1];strcpy(buf,other.buf);}~DeepBuffer(){delete[]buf;}};1.5 值类别控制移动构造触发普通左值优先调用拷贝构造亡值/纯右值优先调用移动构造std::move不移动资源仅仅转换值类别允许编译器匹配移动重载std::string s{demo};std::string s1s;// 左值 → 拷贝构造std::string s2std::move(s);// move转为亡值 → 移动构造// 移动后s处于合法但未指定状态不要再随意访问s内部资源二、移动语义、拷贝消除 三/五/零法则2.1 移动语义核心转移堆资源所有权避免昂贵深拷贝源对象变为有效但可丢弃状态。classBuffer{public:char*data;size_t len;Buffer(size_t n):len(n),data(newchar[n]){}// 移动构造Buffer(Bufferother)noexcept{dataother.data;lenother.len;other.datanullptr;// 源对象置空防止析构释放other.len0;}// 移动赋值Bufferoperator(Bufferother)noexcept{if(thisother)return*this;delete[]data;dataother.data;lenother.len;other.datanullptr;other.len0;return*this;}// 拷贝构造深拷贝Buffer(constBufferother){lenother.len;datanewchar[len];memcpy(data,other.data,len);}~Buffer(){delete[]data;}};voidtest_move(){Bufferb1(1024);Buffer b2std::move(b1);// 移动构造无新堆分配}2.2 拷贝消除 Copy ElisionURVO (RVO) 无名返回值优化返回临时纯右值C17 强制优化NRVO 具名返回值优化返回函数内局部具名对象可选优化// URVO C17强制消除临时std::stringcreate_str_urvo(){returnstd::string(hello world);}// NRVO可选优化std::stringcreate_str_nrvo(){std::strings(hello world);returns;}voiddemo_elision(){std::string screate_str_urvo();// 直接在s的内存上构造对象跳过临时拷贝/移动}注意即使被消除对应构造函数依然要求可访问C17 URVO有部分放宽2.3 三五零法则三法则Rule of ThreeC98如果你手动定义以下任意一个应当显式定义/删除全部3个析构函数拷贝构造函数拷贝赋值运算符背景管理堆内存时默认生成的拷贝是浅拷贝必然引发内存错误// 违反三法则反面示例classBadObj{int*p;public:BadObj(){pnewint;}~BadObj(){deletep;}// 未定义拷贝构造、拷贝赋值编译器生成浅拷贝 → 双重释放风险};五法则Rule of FiveC11扩展在三法则基础上增加移动相关函数定义任意一个建议统一管理5个析构函数拷贝构造拷贝赋值移动构造移动赋值classResource{public:int*ptr;Resource(){ptrnewint{0};}~Resource(){deleteptr;}// 拷贝Resource(constResourceo);Resourceoperator(constResourceo);// 移动Resource(Resourceo)noexcept;Resourceoperator(Resourceo)noexcept;};零法则Rule of Zero现代C推荐最优实践不要手动管理裸资源使用unique_ptr、容器等RAII类型作为成员不自定义析构、拷贝、移动函数依赖编译器自动生成从根源规避内存bug。// 符合零法则classSafeResource{std::unique_ptrintptr;// RAII智能指针接管内存public:SafeResource():ptr(std::make_uniqueint(0)){}// 无需手写析构、拷贝、移动智能指针自动处理生命周期};三、RAII 与资源所有权模型3.1 RAII 资源获取即初始化思想资源在构造时申请析构时自动释放对象生命周期绑定资源生命周期离开作用域自动释放异常场景同样不会泄漏。// 文件RAII简易示例classFileGuard{FILE*fpnullptr;public:FileGuard(constchar*path,constchar*mode){fpfopen(path,mode);}~FileGuard(){if(fp)fclose(fp);}// 禁止拷贝FileGuard(constFileGuard)delete;FileGuardoperator(constFileGuard)delete;};voidread_file(){FileGuardfg(test.txt,r);// 无论正常return、异常抛出离开作用域都会执行析构关闭文件}3.2 三种所有权模型(1独占所有权 std::unique_ptr资源同一时刻仅属于一个智能指针只允许移动禁止拷贝开销最低。voidunique_demo(){autop1std::make_uniqueint(100);// auto p2 p1; ❌ 禁止拷贝autop2std::move(p1);// ✅ 转移独占所有权// p1现在为空不再管理资源}(2共享所有权 std::shared_ptr引用计数管理多个指针共同持有资源计数归零释放存在原子计数开销、循环引用风险。适用场景异步任务、多方模块无法确定谁最后使用资源。voidshared_demo(){autos1std::make_sharedint(200);autos2s1;// 共享引用计数1// s1、s2析构计数递减全部销毁后释放堆内存}(3无所有权借用裸指针T*、引用T仅观察资源不负责释放。规范裸指针只做观察者不管理生命周期voidobserve(int*p){if(p)std::cout*p;}voiddemo(){autoupstd::make_uniqueint(666);observe(up.get());// 借用不转移所有权}3.3 weak_ptr配合shared_ptr不增加引用计数解决循环引用可以尝试提升为shared_ptr判断资源是否存活structNode{intval;std::weak_ptrNodenext;// 使用weak_ptr避免循环引用};3.4 接口设计通过类型显式表达所有权voidfunc1(int*p);// 借用无所有权voidfunc2(std::unique_ptrintp);// 调用方转移独占所有权voidfunc3(std::shared_ptrintp);// 建立共享所有权四、内存编码工程规范非必要不主动new/delete手动管理堆内存优先栈对象、std::vector、std::string等容器// 推荐std::vectorintarr(100);// 不推荐int*arrnewint[100];delete[]arr;需要堆内存优先std::unique_ptr独占首选非必要不使用std::shared_ptr仅生命周期无法静态确定时使用异步、多模块共享裸指针仅用作观察禁止利用裸指针承担内存释放职责遵循Rule of Zero优先依靠RAII封装资源

相关新闻

深入解析微控制器时钟系统:从原理到实践,掌握ARM Cortex-M内核MCU时钟配置

深入解析微控制器时钟系统:从原理到实践,掌握ARM Cortex-M内核MCU时钟配置

1. 微控制器时钟系统:嵌入式系统的“心跳”之源 在嵌入式开发领域,无论是驱动一个简单的LED闪烁,还是处理复杂的网络通信,一切有序工作的背后,都离不开一个核心——时钟系统。你可以把它想象成整个微控制器&#xff08…

2026/10/5 6:49:00 阅读更多 →
提示工程架构师:AI交互设计的核心技术解析

提示工程架构师:AI交互设计的核心技术解析

1. 提示工程架构师的角色定位与技术栈解析 提示工程架构师是AI时代新兴的技术岗位,主要负责设计、优化和管理AI系统的交互接口与指令体系。这个角色需要同时具备自然语言处理、心理学和系统工程的多学科知识,其核心工作是通过结构化提示词(pr…

2026/10/12 11:18:16 阅读更多 →
MSPM0看门狗定时器(IWDT/WWDT)原理、配置与嵌入式系统抗干扰设计

MSPM0看门狗定时器(IWDT/WWDT)原理、配置与嵌入式系统抗干扰设计

1. 项目概述在嵌入式系统开发,尤其是工业控制、汽车电子或医疗设备这类对可靠性要求极高的领域,系统死机或程序跑飞是绝对不能容忍的。想象一下,一个控制电机运转的微控制器因为电磁干扰或软件缺陷卡死在一个循环里,轻则设备停机&…

2026/10/10 22:22:38 阅读更多 →

最新新闻

CC Workflow Studio 扩展与 Webview 间 AI 工作流生成消息契约详解

CC Workflow Studio 扩展与 Webview 间 AI 工作流生成消息契约详解

AI 应用Agent 工作流开发工具MCP 服务 【免费下载链接】cc-wf-studio CC Workflow Studio 项目地址: https://gitcode.com/gh_mirrors/cc/cc-wf-studio 点击查看 免费下载 本篇技术指南以 ai-generation-messages.md 为核心文档,系统讲解 CC Workflow S…

2026/10/13 1:53:15 阅读更多 →
Godot 位图资源导入详解:ResourceImporterBitMap 与 BitMap 点击遮罩的创建与实战

Godot 位图资源导入详解:ResourceImporterBitMap 与 BitMap 点击遮罩的创建与实战

文档教程游戏开发 【免费下载链接】godot-docs Godot Engine official documentation 项目地址: https://gitcode.com/GitHub_Trending/go/godot-docs 点击查看 免费下载 本篇指南围绕 Godot 官方文档中 ResourceImporterBitMap 类参考展开,系统讲解 Bi…

2026/10/13 1:53:15 阅读更多 →
C#串口程序现场稳定运行:四大关键关卡与排查实战指南

C#串口程序现场稳定运行:四大关键关卡与排查实战指南

C# 串口程序在开发环境跑得好好的,代码自测、工装验证样样精通,结果一到客户现场就露馅。乱码、收发超时、程序假死、设备掉线,你满头大汗在现场改代码,客户就在背后看着,压力直接拉满。这也不是我一个人踩过的坑&…

2026/10/13 1:53:15 阅读更多 →
台风烧录器实战:从内存SPD读取到安全修改超频参数

台风烧录器实战:从内存SPD读取到安全修改超频参数

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 1:53:15 阅读更多 →
从手写数字识别入门BP反向传播:原理到实战全解析

从手写数字识别入门BP反向传播:原理到实战全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 1:53:15 阅读更多 →
NCCL 参数访问 API 完全指南:Handle 绑定与 Key 直查两种运行时参数读取方式

NCCL 参数访问 API 完全指南:Handle 绑定与 Key 直查两种运行时参数读取方式

高性能计算通信深度学习分布式训练 【免费下载链接】nccl Optimized primitives for collective multi-GPU communication 项目地址: https://gitcode.com/gh_mirrors/nc/nccl 点击查看 免费下载 NCCL(NVIDIA Collective Communications Library&#x…

2026/10/13 1:52:15 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →