• C++ 智能指针


    C++中的智能指针是一种用于自动管理动态分配内存的对象。通过使用智能指针,开发者可以避免由于忘记释放内存而导致的内存泄漏,以及由于多次释放同一块内存而导致的双重释放问题。

    C++标准库提供了几种不同类型的智能指针,包括std::unique_ptr、std::shared_ptr、std::weak_ptr和std::auto_ptr(但std::auto_ptr在C++11及以后的版本中已被废弃)。

    1、std::unique_ptr

    std::unique_ptr的主要特点是“独占所有权”,在给定时间内只有唯一一个指针可以拥有对象,当这个指针被销毁(例如,离开其作用域)时,它所指向的对象也会被自动删除。

    移动语义:允许资源的所有权从一个std::unique_ptr对象转移到另一个std::unique_ptr对象,通过std::move函数实现;

    空指针检查:std::unique_ptr提供了成员函数get方法来获取所管理的指针,如果是空指针则表示不拥有任何资源;

    自定义删除器:std::unique_ptr允许用户指定一个自定义的删除器(可以是一个函数、函数对象或 lambda 表达式),用于在资源释放时执行特定的操作;

    内部实现:std::unique_ptr是一个模板类,定义在头文件中,它的构造函数接受一个原始指针,还可以选择一个自定义的删除器。它禁用了复制构造和赋值操作。

    std::unique_ptrdecltype(deleter_wrapper)> ptr(new MyClass(42), deleter_wrapper);

    使用技巧: 在创建std::unique_ptr时推荐使用std::make_unique函数来替代直接调用构造函数。

    1. // 当ptr离开作用域时,int对象会被自动删除
    2. std::unique_ptr<int> ptr(new int(5)); // 直接使用new运算符构造
    3. std::unique_ptr<int> ptr = std::make_unique<int>(42); // 使用std::make_unique构造

    std::make_unique 是 C++14 引入的一个智能指针辅助函数,它用于动态分配一个对象并初始化一个 std::unique_ptr 智能指针来管理这个对象的生命周期。使用 std::make_unique 比直接使用 new 运算符并构造 std::unique_ptr 更为安全和高效,因为它可以将对象和其控制块分配在连续的内存中。如果在构造函数内部抛出了异常,std::make_unique 会确保内存被正确释放,从而避免了内存泄漏。

    2、std::shared_ptr

    std::shared_ptr的主要特点是“共享所有权。它使用一个引用计数机制来管理资源的生命周期,确保当没有任何std::shared_ptr指向该资源时,资源会被自动释放。

    引用计数:每个std::shared_ptr对象都持有一个指向控制块的指针,这个控制块包含一个引用计数和指向被管理资源的指针。当一个新的std::shared_ptr被创建和引用赋值时,控制块的引用计数会增加。当一个std::shared_ptr被销毁或被重置为另一个资源时,控制块的引用计数会减少。

    控制块:控制块包含一个引用计数和指向被管理资源的指针,还包含删除器和自定义分配器的指针,引用计数变为0时释放资源。

    自定义删除器:std::shared_ptr允许用户提供一个自定义的删除器,该删除器在引用计数为0时调用,用于释放资源。

    线程安全:std::shared_ptr的引用计数是线程安全的,引用计数的增加和减少操作通常使用原子操作来实现。

    循环引用:std::shared_ptr可以有效地管理资源的生命周期,但它无法解决循环引用问题。为解决循环引用问题引入了std::weak_ptr。

    1. std::shared_ptr<int> ptr1 = std::make_shared<int>(5);
    2. std::shared_ptr<int> ptr2 = ptr1; // ptr1和ptr2共享所有权
    3. // 当ptr1和ptr2都离开作用域时,int对象才会被删除

    3、std::weak_ptr

    std::weak_ptr是一种弱引用智能指针,不会增加对象的引用计数,也不影响对象的声明周期。
    内部结构:std::weak_ptr内部维护了一个指向引用计数对象的指针,这个引用计数对象与std::shared_ptr共享。引用计数对象包含两个重要的计数:强引用计数(由std::shared_ptr管理)和弱引用计数(由std::weak_ptr管理)。

    主要操作:std::weak_ptr 可以从 std::shared_ptr 或另一个 std::weak_ptr 构造,构造过程中不会增加强引用计数,但会增加弱引用计数。std::weak_ptr 提供了 lock 成员函数,用于尝试获取一个指向同一对象的 std::shared_ptr。std::weak_ptr 提供了 expired 成员函数,用于检查所指向的对象是否已经被销毁。如果对象已经被销毁,expired 返回 true;否则返回 false。

    生命周期:当 std::shared_ptr 释放了所管理的对象时,对象的强引用计数会变为 0,对象会被删除。但此时弱引用计数可能不为 0(因为有 std::weak_ptr 指向它),因此对象的控制块(包含引用计数信息的结构)不会被立即销毁。只有当最后一个指向该对象的 std::weak_ptr 被销毁时,弱引用计数才会变为 0,此时控制块才会被销毁,从而完全释放资源。

    注意事项:避免过度使用 lock 函数,因为它可能会增加引用计数并进行内存分配,从而影响性能。在使用 std::weak_ptr 观测所指向对象的生命周期时,应该始终使用 lock 或 expired 函数来检查对象是否存在,以避免在访问已销毁对象时产生未定义行为。

    1. // 假设有两个shared_ptr相互引用,形成循环引用
    2. // 使用weak_ptr可以打破这种循环引用

    4、std::auto_ptr(已废弃)

    std::auto_ptr是C++98中引入的一个智能指针,但在C++11及以后的版本中已被废弃,因为它存在所有权转移的问题,可能导致意外的行为。因此,建议不要使用std::auto_ptr。


     

  • 相关阅读:
    使用DESeq2进行转录组原始count标准化和差异分析
    JSP合同信息管理系统
    基于模板匹配算法的交通标志识别(MATLAB源码)
    Flink实时计算中台Kubernates功能改造点
    Flutter折腾学习成长记(25)
    打码半年,开源一款自定义大屏设计软件!
    记录一次Maven依赖传递,模块之间依赖版本不一致问题
    2021年下半年软件设计师下午真题答案及解析(五)
    【云原生 | Kubernetes 系列】----K8s持续集成与部署
    美团MTCTF 2022 ret2libc_aarch64 pwn解
  • 原文地址:https://blog.csdn.net/wy749929317/article/details/139748304