C++ 现代编程实践:用 make_unique 告别裸 new/delete

发布时间:2026/9/28 6:44:26

C++ 现代编程实践:用 make_unique 告别裸 new/delete
1. 为什么应该抛弃裸 new/delete在 C11 之前动态内存管理几乎是开发者的日常一个new配上若干个delete还要小心异常安全和所有权问题。手动管理内存至少会带来三大痛点内存泄漏delete忘记调用、提前return或者抛出异常时资源就会丢失二次释放与野指针重复删除同一块内存或继续使用已释放的指针会导致未定义行为所有权混乱团队协作时很难从裸指针一眼看出“谁负责释放”容易写出 bug。自 C11 以来标准库提供了std::unique_ptr和std::make_uniqueC14 起让我们可以彻底告别显式new和delete。本文将介绍如何安全、高效地替换现有代码中的裸指针并解释背后的设计动机。2. make_unique 基本用法std::make_unique是创建std::unique_ptr的工厂函数它直接在堆上构造对象并返回一个独占所有权的智能指针。基本形式为auto p std::make_uniqueWidget(arg1, arg2);等价于原先的Widget* raw new Widget(arg1, arg2);但好处是不需要写delete离开作用域时自动释放异常安全即使构造函数抛出异常也不会泄漏先前分配的资源明确表达了“独占所有权”的语义避免了写两次类型名auto配合make_unique减少冗余。3. 替换模式从 new/delete 到 unique_ptr下面通过几个常见场景展示如何系统地将裸指针代码迁移到make_unique。3.1 普通堆对象// 旧代码手动 new/delete void useWidget() { Widget* w new Widget(100); // ... delete w; // 容易忘记还可能被异常跳过 } // 新代码make_unique void useWidget() { auto w std::make_uniqueWidget(100); // ... 不再需要 delete }3.2 类成员变量class Manager { // 旧裸指针 手动管理 Widget* w_; public: Manager() : w_(new Widget(42)) {} ~Manager() { delete w_; } // 还需要拷贝/移动操作……一团乱 }; class Manager { // 新unique_ptr 自动管理生命周期 std::unique_ptrWidget w_; public: Manager() : w_(std::make_uniqueWidget(42)) {} // 析构函数自动释放无需手写 // 移动语义天然支持禁止拷贝 };3.3 容器中的对象指针// 旧vector 中存裸指针销毁前必须逐个 delete std::vectorWidget* widgets; widgets.push_back(new Widget(1)); widgets.push_back(new Widget(2)); for (auto p : widgets) delete p; // 极易漏删 // 新存 unique_ptrclear/析构自动释放 std::vectorstd::unique_ptrWidget widgets; widgets.push_back(std::make_uniqueWidget(1)); widgets.push_back(std::make_uniqueWidget(2)); // 容器销毁时自动释放所有 Widget4. 为什么推荐 make_unique 而不是直接 new unique_ptr你当然可以这样写std::unique_ptrWidget p(new Widget(arg));但是仍然显式写了new违背了“禁止显式 new/delete”的原则。更重要的是make_unique提供了额外的异常安全保证和优化可能某些实现可以减少一次内存分配。此外工厂函数风格使得代码意图更清晰、更容易审计。5. 注意事项与边界场景C11 兼容std::make_unique是 C14 新增的如果还停留在 C11可以自己实现一个简单的版本。自定义删除器unique_ptr支持自定义删除器但make_unique无法传递删除器此时仍需使用new构造unique_ptr。不过现代代码中这类场景很少且通常可以用shared_ptr或封装类替代。数组类型std::make_unique也支持数组例如std::make_uniquechar[](1024)。不过要注意unique_ptrT[]的删除器与标量不同不要混淆。所有权转移需要传递所有权时使用std::move转移unique_ptr本身而不是转移裸指针。与共享所有权的区别当确实需要共享所有权时再考虑std::make_shared。不要因为懒得设计所有权就用shared_ptr一把梭。6. 在团队中推行“禁止 new/delete”可以借助静态分析工具如 clang-tidy 的modernize-make-unique检查项或编译器警告来强制执行这一规则。团队规范中明确写清楚绝对不允许出现裸new和delete所有动态分配都通过std::make_unique或std::make_shared完成裸指针仅用于非拥有性引用且需要标明“不负责释放”。这样不仅能大幅减少内存相关 bug也使得代码更容易被新成员理解和维护。7. 总结用std::make_unique替代裸new/delete是现代 C 的最佳实践之一。它消除了手动资源管理的麻烦提升了异常安全性并且让所有权语义一目了然。本文提供的替换模式和注意事项可以帮助你平滑迁移现有代码并建立一套可靠的编码规范。从今天起让我们对显式new和delete说“不”。

相关新闻

3步掌握小红书无水印下载:新手也能快速上手的XHS-Downloader工具

3步掌握小红书无水印下载:新手也能快速上手的XHS-Downloader工具

2026/9/28 6:44:09

3步掌握小红书无水印下载:新手也能快速上手的XHS-Downloader工具 【免费下载链接】XHS-Downloader 小红书(XiaoHongShu、RedNote)链接提取/作品采集工具:提取账号发布、收藏、点赞、专辑作品链接;提取搜索结果作品、用…

STM32L152ZD与MCP3551高精度ADC接口设计与优化

STM32L152ZD与MCP3551高精度ADC接口设计与优化

2026/9/27 17:48:17

1. MCP3551与STM32L152ZD的硬件架构解析MCP3551是Microchip公司推出的一款22位Δ-Σ型模数转换器,采用单电源供电(2.7V-5.5V),内部集成可编程增益放大器(PGA)和低噪声基准电压源。其核心特性包括&#xff1…

蓝牙5.4 LE Audio与STM32的无线音频传输方案

蓝牙5.4 LE Audio与STM32的无线音频传输方案

2026/8/26 19:25:53

1. 项目背景与硬件选型解析 在无线音频传输领域,Bluetooth 5.4标准带来了革命性的改进,特别是LE Audio的引入彻底改变了传统蓝牙音频的传输方式。我们选择IDC777-1蓝牙模块与STM32F417ZG微控制器的组合,正是看中了这套方案在低功耗和高音质之…

CANN/GE ACL数据集缓冲区添加函数

CANN/GE ACL数据集缓冲区添加函数

2026/9/28 4:08:17

aclmdlAddDatasetBuffer 【免费下载链接】ge GE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、Te…

用ffmpeg高效批量调整图片尺寸的实战指南

用ffmpeg高效批量调整图片尺寸的实战指南

2026/9/27 1:30:29

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

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱

2026/9/28 2:15:29

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱 【免费下载链接】transformers 🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and mu…

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南

2026/9/28 3:14:54

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南 【免费下载链接】rustfs 🚀2.3x faster than MinIO for 4KB object payloads. RustFS is an open-source, S3-compatible high-performance object storage system sup…

Java Integer缓存揭秘:128陷阱原理、避坑与面试全解

Java Integer缓存揭秘:128陷阱原理、避坑与面试全解

2026/9/28 3:58:00

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

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据

2026/9/28 3:47:14

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据 【免费下载链接】rustfs 🚀2.3x faster than MinIO for 4KB object payloads. RustFS is an open-source, S3-compatible high-performance object storage system supporting mi…

远程协作的工作台整理

远程协作的工作台整理

2026/9/26 14:29:04

远程协作的工作台整理远程协作的核心不是再加一个工具,而是让交接信息足够完整。异步任务要写明目标、输入位置、完成标准和需要决策的人。 工作台的最小配置 将日程、待办、代码和沟通入口收拢到少数固定位置;通知按紧急程度分层。工作台不需要模仿办公…

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

2026/9/28 5:05:21

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

2026/9/26 23:35:16

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…