当前位置: 首页 > ops >正文

make_unique

在 C++ 中,make_unique 是 C++14 引入的一个辅助函数,用于更安全、更便捷地创建 std::unique_ptr 智能指针。相较于直接使用 new 表达式初始化 unique_ptrmake_unique 的安全性主要体现在以下几个方面:

1. 避免资源泄漏(异常安全)

直接使用 new 的风险

当用 new 手动创建对象并传递给智能指针时,若初始化过程中发生异常(例如构造函数抛出异常或后续代码出错),可能导致资源未被智能指针接管而泄漏。
示例(风险场景)

// 假设 func() 可能抛出异常
std::unique_ptr<int> p(new int(42));  // 安全:直接初始化
std::unique_ptr<int> p1(new int(42), func);  // 安全:deleter是栈上对象
std::unique_ptr<int> p2(new int(42), std::bind(func, get_data()));  // 危险!
  • std::unique_ptr<int> p2(...) 中,表达式执行顺序为:
    1. 执行 get_data() 获取参数(可能抛出异常)。
    2. 执行 new int(42) 分配内存(可能抛出 bad_alloc)。
    3. 执行 std::bind(func, ...) 创建deleter。
    4. 将指针和deleter传入 unique_ptr 构造函数。
  • 风险点:若步骤1或步骤3抛出异常,new int(42) 返回的指针尚未被 unique_ptr 接管,导致内存泄漏。
make_unique 的安全性

make_unique 通过单一表达式完成内存分配、对象构造和智能指针对象的创建,确保在异常发生时资源能被正确释放。
示例(安全版本)

auto p = std::make_unique<int>(42);  // 等价于 unique_ptr<int>(new int(42))
auto p2 = std::make_unique<int>([](int* x){ func(x); });  // 自定义deleter
  • make_unique 内部会直接将 new 表达式的结果传递给 unique_ptr 构造函数,保证内存分配和智能指针初始化在同一作用域内完成,避免中间步骤的异常导致泄漏。

2. 防止裸指针误用

直接使用 new 的隐患

手动使用 new 时,可能意外将裸指针暴露给外部,破坏智能指针的封装性,导致悬空指针或双重释放问题。
示例(错误用法)

int* raw = new int(42);
std::unique_ptr<int> p1(raw);
std::unique_ptr<int> p2(raw);  // 非法!两个智能指针管理同一裸指针,导致双重释放
make_unique 的封装性

make_unique 直接返回 unique_ptr 对象,不暴露裸指针,从源头避免上述问题。
示例(安全用法)

auto p1 = std::make_unique<int>(42);
auto p2 = p1;  // 非法!unique_ptr不可拷贝,避免误操作
auto p3 = std::move(p1);  // 合法!通过移动语义转移所有权

3. 更简洁的语法,减少人为错误

直接使用 new 的冗余

初始化 unique_ptr 时需显式写出类型,容易因类型不匹配导致编译错误。
示例(冗余代码)

std::unique_ptr<std::vector<int>> vec(new std::vector<int>{1, 2, 3});
// 需重复书写类型 `std::vector<int>`
make_unique 的类型推导

make_unique 支持模板类型推导,代码更简洁且不易出错。
示例(类型推导)

auto vec = std::make_unique<std::vector<int>>({1, 2, 3});
// 自动推导为 unique_ptr<std::vector<int>>,无需重复书写类型

4. 对数组和聚合类型的友好支持

数组初始化(C++14+)

make_unique 支持直接创建数组类型的 unique_ptr,避免手动处理 [] 的问题。
示例

// 分配包含5个int的数组(值初始化为0)
auto arr = std::make_unique<int[]>(5);  // 等价于 unique_ptr<int[]>(new int[5]())
arr[0] = 10;// 列表初始化(C++17+)
auto arr2 = std::make_unique<int[]>({1, 2, 3});  // 数组大小为3
聚合类型初始化(C++17+)

对于没有构造函数的聚合类型(如 struct),make_unique 支持直接初始化成员。
示例

struct Point { int x, y; };  // 聚合类型
auto p = std::make_unique<Point>(Point{1, 2});  // C++14写法
auto p2 = std::make_unique<Point>(1, 2);         // C++17简化写法(直接传递成员值)

5. 与其他智能指针和库的兼容性

make_unique 是 C++ 标准库的一部分,与 std::make_shared(用于 shared_ptr)风格统一,便于代码维护和团队协作。

  • 例如,在需要返回智能指针的函数中,使用 make_unique 可确保接口的一致性:
    std::unique_ptr<MyClass> createObject() {return std::make_unique<MyClass>(arg1, arg2);  // 简洁且安全
    }
    

总结:make_unique 的核心优势

特性make_unique直接使用 new + unique_ptr
异常安全单一表达式完成分配和初始化,避免泄漏可能因初始化顺序导致泄漏
封装性不暴露裸指针,禁止非法拷贝可能意外传递裸指针,导致双重释放
语法简洁性自动类型推导,减少冗余需显式指定类型,容易出错
数组/聚合支持原生支持数组和聚合类型初始化需手动处理 [] 和构造函数
代码一致性make_shared 风格统一,易于维护风格不统一,可能混合裸指针和智能指针

何时不使用 make_unique

  • 需要自定义deleter的非默认构造场景
    若deleter需要在 unique_ptr 构造时动态生成(如依赖外部参数),仍需手动使用 new
    示例
    // 自定义deleter依赖外部函数指针
    void(*deleter)(int*) = my_custom_deleter;
    auto p = std::unique_ptr<int>(new int(42), deleter);
    // 无法用make_unique直接生成,需手动处理
    
  • C++14 之前的编译器
    若项目需兼容 C++11,需手动实现类似 make_unique 的辅助函数(C++11 标准库未包含 make_unique,但可自行实现)。

最佳实践

  • 优先使用 make_unique:只要场景允许,尽量用 make_unique 创建 unique_ptr,避免手动操作 new
  • 结合RAII原则:将资源管理完全交给智能指针,避免在作用域内显式调用 delete
  • 避免裸指针传递:函数参数和返回值尽量使用智能指针或引用,减少裸露资源的风险。

通过 make_unique,C++ 提供了一种更安全、更现代的动态内存管理方式,显著降低了传统 new/delete 模式下的常见错误。

http://www.xdnf.cn/news/10573.html

相关文章:

  • 基于LangChain的AI助手开发:从零到上线
  • 案例:TASK OA
  • Pycharm的终端无法使用Anaconda命令行问题详细解决教程
  • 兰亭妙微十六年高水准交互设计公司
  • php 各版本下载
  • 探索大语言模型(LLM):RSE流程详解——从文档中精准识别高相关片段
  • 50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | Form Wave(表单label波动效果)
  • 力扣刷题(第四十五天)
  • navicate菜单栏不见了怎么办
  • cursor如何开启自动运行模式
  • PH热榜 | 2025-05-31
  • Docker常用命令详解与高效记忆指南
  • Android Studio历史版本下载地址汇总
  • 【软件测试】web自动化:Pycharm+Selenium+Firefox(一)
  • 【动画】unity中实现骨骼蒙皮动画
  • 使用FastAPI构建车牌检测识别服务
  • 「Python教案」字符串格式化操作
  • hooks组件-useState
  • 散列表(哈希表)
  • 函数调用的机器级实现(二):栈帧的访问与切换机制
  • 【笔记】为 Python 项目安装图像处理与科学计算依赖(MINGW64 环境)
  • 用wireshark抓包分析学习USB协议
  • 浅写弱口令与命令爆破
  • Cursor 编辑器介绍:专为程序员打造的 AI 编程 IDE
  • Python项目结构
  • 录屏不再难,从功能到体验深度测评
  • MPTCP 聚合吞吐
  • LRU和LFU缓存策略
  • ESP32系列AT固件快速开发——Wi-Fi MQTT
  • 【笔记】Windows系统部署suna基于 MSYS2的Poetry 虚拟环境backedn后端包编译失败处理