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

【读书笔记】《Effective Modern C++》第4章 Smart Pointers

《Effective Modern C++》第4章 Smart Pointers

一、使用 std::unique_ptr 管理独占所有权(Item 18)

  1. 基本概念
    std::unique_ptr 提供对动态分配资源的独占所有权管理。与裸指针不同,unique_ptr 在离开作用域或被重置时自动释放所管理的资源。它禁止拷贝,只能移动。

  2. 使用方式
    推荐工厂函数方式创建:

    auto up = std::make_unique<Foo>(arg1, arg2);
    

    当需要转移所有权时:

    std::unique_ptr<Foo> up2 = std::move(up);
    // 此时 up 为空,up2 拥有资源
    
  3. 自定义删除器
    对于非 new 分配的资源,如 FILE* 或自定义句柄,可传入删除器类型:

    std::unique_ptr<FILE, decltype(&fclose)> fp(fopen("data.txt", "r"), &fclose);
    

    删除器在 unique_ptr 析构时被调用,保证资源释放。

  4. 注意事项

    • 禁止拷贝可防止重复释放;
    • 作为成员变量时,可用 = default 或手动定义移动构造/赋值;
    • 不要将裸指针与 unique_ptr 混合管理同一资源。

二、使用 std::shared_ptr 管理共享所有权(Item 19)

  1. 基本概念
    std::shared_ptr 通过内部控制块维护引用计数,允许多方共享同一对象。最后一个 shared_ptr 析构时,自动释放资源。

  2. 使用方式
    推荐工厂函数:

    auto sp1 = std::make_shared<Foo>(arg);
    auto sp2 = sp1;   // 引用计数增至 2
    sp1.reset();      // 计数减至 1
    // 最后 sp2 离开作用域时释放 Foo
    
  3. 性能与成本

    • 控制块与对象默认一次分配;
    • 引用计数操作是原子级别开销;
    • 拷贝和析构时都要修改计数。
  4. 循环引用问题
    当对象 A 和 B 相互持有 shared_ptr,会导致引用计数永不归零。必须通过 weak_ptr 打破循环。

三、使用 std::weak_ptr 管理可能失效的观察型指针(Item 20)

  1. 基本概念
    std::weak_ptr 是对 shared_ptr 管理资源的非拥有型引用,不增加引用计数。它记录 control block 的弱引用,可检测资源是否已释放。

  2. 使用方式

    std::shared_ptr<Foo> sp = std::make_shared<Foo>();
    std::weak_ptr<Foo> wp = sp;  // 计数不变if (auto guard = wp.lock()) {// guard 为 shared_ptr,安全访问guard->method();
    } else {// 对象已销毁
    }
    
  3. 应用场景

    • 观察者模式、缓存实现、回调注册时,不希望延长对象生命周期;
    • 打破 shared_ptr 循环引用的一端。
  4. 注意事项

    • 使用 lock() 获取 shared_ptr 并检查是否为空;
    • 避免直接将 weak_ptr 转为裸指针;
    • expired() 可用于简单过期检测,但 lock() 更安全。

四、优先使用 std::make_unique 和 std::make_shared(Item 21)

  1. 问题及原因
    直接 new 后再构造智能指针存在两次内存分配和潜在异常安全漏洞:一旦在 new 后抛出,容易泄漏。

  2. make 工厂函数优势

    • 单次内存分配:make_shared 在一次分配中创建控制块和对象;
    • 异常安全:资源在构造过程中即被智能指针管理,不会泄漏。
  3. 示例对比

    // 不推荐
    std::unique_ptr<Foo> up(new Foo(args));
    std::shared_ptr<Foo> sp(new Foo(args));// 推荐
    auto up2 = std::make_unique<Foo>(args);
    auto sp2 = std::make_shared<Foo>(args);
    
  4. 特殊情况

    • 需要自定义删除器时,仍需手动 new 并传入删除器;
    • make_shared 无法分离控制块内存,若希望控制释放时机可考虑手动创建。

五、Pimpl 习惯用法中在实现文件定义特殊成员函数(Item 22)

  1. Pimpl 模式目的
    隐藏实现细节、减少头文件依赖、加快编译速度。头文件中声明不完整类型,实际数据保存在实现类 Impl 中。

  2. 头文件示例(Widget.h)

    class Widget {
    public:Widget();~Widget();Widget(const Widget&);Widget& operator=(const Widget&);
    private:struct Impl;std::unique_ptr<Impl> pImpl;
    };
    
  3. 实现文件示例(Widget.cpp)

    struct Widget::Impl {// 数据成员
    };Widget::Widget() : pImpl(std::make_unique<Impl>()) {}
    Widget::~Widget() = default;
    Widget::Widget(const Widget& w): pImpl(std::make_unique<Impl>(*w.pImpl)) {}
    Widget& Widget::operator=(const Widget& w) {*pImpl = *w.pImpl;return *this;
    }
    
  4. 原因与好处

    • Impl 定义对外部不可见,确保封装性;
    • 修改 Impl 后只需重新编译 cpp,减少依赖传播;
    • 特殊成员函数在 cpp 中定义时,Impl 完整可见,避免不完整类型使用错误。

总结

本章围绕智能指针的五个核心要点展开,从独占所有权到共享所有权,再到观察型 weak_ptr,以及工厂函数与 Pimpl 相结合的模式实践,全面阐明了现代 C++ 中资源管理的最佳实践。通过合理选用 unique_ptr、shared_ptr 和 weak_ptr,并配合 make_xxx 工厂函数和 Pimpl 隐藏实现细节,能够编写安全、高效且易于维护的 C++ 应用。

http://www.dtcms.com/a/277169.html

相关文章:

  • Node.js 聊天内容加密解密实战教程(含缓存密钥优化)
  • 4. 关于CEF3 使用的一些记录及仓颉端封装的情况
  • 手写muduo笔记
  • package.json 与 package-lock.json
  • 笔记/sklearn中的数据划分方法
  • 流程控制:从基础结构到跨语言实践与优化
  • 博客项目 laravel vue mysql 第五章 标签功能
  • 前端性能优化利器:懒加载技术原理与最佳实践
  • JAVA JVM虚拟线程
  • 第三章-提示词-解锁Prompt提示词工程核销逻辑,开启高效AI交互(10/36)
  • Vue3 Diff 算法片段解析:新旧节点队列之乱序比对与更新策略
  • 7月13日星期日今日早报简报微语报早读
  • Python PyWhat详解:一款高效的数据类型识别与扫描工具
  • 把固态电池当“显卡”用:基于Li⁺迁移率的矩阵乘法加速器——电解质-权重共设计框架与FP8训练实战
  • C++--List的模拟实现
  • 深入解析Hadoop RPC:技术细节与推广应用
  • vue3 ref vs reactive值的修改
  • 自动润滑系统:从 “盲目养护“ 到智能精注的工业运维革命
  • 【芯片笔记】ADF4159
  • 详解Linux下多进程与多线程通信(一)
  • python:使用openpyxl库,实现excel表格的创建、查询(读取)、修改、插入数据
  • LVS负载均衡集群概述
  • 论文笔记:AnImitation Learning Approach for Cache Replacement
  • iOS高级开发工程师面试——架构设计
  • MailSpring
  • [Subtitle Edit] 语言文件管理.xml | 测试框架(VSTest) | 构建流程(MSBuild) | AppVeyor(CI/CD)
  • 006_测试评估与安全实践
  • 设计模式之工厂模式:对象创建的智慧之道
  • 设计模式-门面模式
  • CAU数据挖掘第四章 分类问题