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

全面理解-c++11中的智能指针

在 C++ 中,智能指针(Smart Pointers) 是用于自动管理动态分配内存的类模板,遵循 RAII(Resource Acquisition Is Initialization) 原则,确保资源在生命周期结束时被正确释放,避免内存泄漏。C++11 引入了三种主要的智能指针:std::unique_ptrstd::shared_ptr 和 std::weak_ptr,取代了 C++98 中不安全的 std::auto_ptr


1. 为什么需要智能指针?

  • 手动管理内存的痛点

    • 忘记 delete 导致内存泄漏。

    • 重复 delete 导致未定义行为。

    • 异常安全问题(未捕获异常时资源无法释放)。

  • 智能指针的核心作用

    • 自动释放内存:对象生命周期结束时自动调用 delete

    • 明确所有权语义:通过所有权模型管理资源。


2. 主要智能指针类型

(1) std::unique_ptr(独占所有权)
  • 所有权模型:唯一拥有资源,不可复制,但可通过 std::move 转移所有权。

  • 适用场景

    • 资源有唯一拥有者。

    • 需要轻量级、零开销的内存管理。

  • 基本用法

    #include <memory>
    
    // 创建 unique_ptr
    std::unique_ptr<int> ptr1 = std::make_unique<int>(10);  // C++14 起推荐
    std::unique_ptr<int> ptr2(new int(20));                 // 直接构造
    
    // 转移所有权
    std::unique_ptr<int> ptr3 = std::move(ptr1);  // ptr1 变为 nullptr
    
    // 自定义删除器(可选)
    auto deleter = [](int* p) { delete p; };
    std::unique_ptr<int, decltype(deleter)> ptr4(new int(30), deleter);
(2) std::shared_ptr(共享所有权)
  • 所有权模型:通过引用计数(use_count())管理资源,多个指针共享所有权。

  • 适用场景

    • 多个对象需要共享同一资源。

    • 资源生命周期不确定,需自动管理。

  • 基本用法

    // 创建 shared_ptr
    std::shared_ptr<int> ptr1 = std::make_shared<int>(10);  // 推荐(高效)
    std::shared_ptr<int> ptr2(new int(20));                 // 直接构造
    
    // 共享所有权
    std::shared_ptr<int> ptr3 = ptr1;  // 引用计数 +1(ptr1.use_count() == 2)
    
    // 自定义删除器(可选)
    std::shared_ptr<int> ptr4(new int(30), [](int* p) { delete p; });
(3) std::weak_ptr(弱引用)
  • 所有权模型:不增加引用计数,用于解决 shared_ptr 的循环引用问题。

  • 适用场景

    • 观察 shared_ptr 管理的资源,不参与所有权管理。

    • 打破 shared_ptr 的循环引用(如双向链表、观察者模式)。

  • 基本用法

    std::shared_ptr<int> sharedPtr = std::make_shared<int>(42);
    std::weak_ptr<int> weakPtr = sharedPtr;
    
    // 使用时提升为 shared_ptr
    if (auto tempPtr = weakPtr.lock()) {  // 检查资源是否有效
        std::cout << *tempPtr << std::endl;  // 输出 42
    }
(4) std::auto_ptr(已弃用)
  • 问题:所有权转移语义不明确(通过拷贝构造函数转移所有权),易导致悬空指针。

  • 替代方案:使用 std::unique_ptr


3. 智能指针的核心对比

特性std::unique_ptrstd::shared_ptrstd::weak_ptr
所有权独占共享无(弱引用)
拷贝语义禁止(只能移动)允许(引用计数增加)允许(不增加引用计数)
性能开销引用计数操作(原子操作)
循环引用处理不适用无法解决可解决
自定义删除器支持(模板参数)支持(构造函数参数)不适用

4. 使用建议

  1. 优先使用 std::make_unique 和 std::make_shared

    • 更高效(减少内存分配次数)。

    • 异常安全。

    auto ptr = std::make_shared<int>(42);  // 替代 new
  2. 避免裸指针与智能指针混用

    int* rawPtr = new int(10);
    std::shared_ptr<int> ptr(rawPtr);  // ❌ 危险:多个 shared_ptr 可能管理同一裸指针
  3. 解决循环引用

    • 使用 std::weak_ptr 断开 shared_ptr 的循环依赖。

    class B;  // 前向声明
    
    class A {
    public:
        std::shared_ptr<B> bPtr;
    };
    
    class B {
    public:
        std::weak_ptr<A> aPtr;  // 使用 weak_ptr 代替 shared_ptr
    };
  4. 传递智能指针的规则

    • 函数参数

      • 如果函数需要接管所有权 → 按值传递 std::unique_ptr

      • 如果函数只是使用资源 → 传递裸指针或引用。

      void takeOwnership(std::unique_ptr<int> ptr);  // 接管所有权
      void useResource(const int* ptr);              // 仅使用资源


5. 智能指针的底层原理

  • std::unique_ptr

    • 内部封装一个裸指针,删除时调用 delete 或自定义删除器。

    • 禁止拷贝构造函数和拷贝赋值运算符。

  • std::shared_ptr

    • 包含两个指针:一个指向对象,一个指向控制块(含引用计数和删除器)。

    • 引用计数为 0 时释放资源。

  • std::weak_ptr

    • 不增加引用计数,但能检测资源是否有效。


6. 示例代码

(1) unique_ptr 管理动态数组
// 管理动态数组(C++11 需要指定删除器,C++14 起可直接用 unique_ptr<T[]>)
std::unique_ptr<int[]> arr(new int[5]{1, 2, 3, 4, 5});
arr[0] = 10;
(2) shared_ptr 的循环引用问题
#include <memory>

class Node {
public:
    std::shared_ptr<Node> next;
};

int main() {
    auto node1 = std::make_shared<Node>();
    auto node2 = std::make_shared<Node>();
    node1->next = node2;  // node1 引用 node2
    node2->next = node1;  // node2 引用 node1 → 循环引用,内存泄漏!
    return 0;
}

解决方案:将其中一个 shared_ptr 替换为 weak_ptr


总结

智能指针是现代 C++ 内存管理的核心工具,通过明确所有权和自动资源释放,显著提升代码安全性和可维护性。根据场景选择:

  • 唯一所有权 → std::unique_ptr

  • 共享所有权 → std::shared_ptr

  • 弱引用观察 → std::weak_ptr

遵循 RAII 原则,避免手动 new/delete,是编写高质量 C++ 代码的关键。

相关文章:

  • C语言初阶牛客网刷题——JZ65 不用加减乘除做加法】【难度:简单】
  • SAIL-RK3576单板运行7b的deepseek对话模型
  • uvm错误记录4
  • wps接入DeepSeek教程
  • 本地安装了mysql导致phpstudy无法启动
  • 解锁OCP认证:通往数据库精英之路
  • 微软AutoGen高级功能——Memory
  • SSM开发(十二) mybatis的动态SQL
  • Mac安装JD-GUI
  • Vue.js 组件开发深入解析:Vue 2 vs Vue 3
  • uniapp开发h5部署到服务器
  • mybatis-plus逆向code generator pgsql实践
  • 3dtiles——Cesium ion for Autodesk Revit Add-In插件
  • 如何在Ubuntu中切换多个PHP版本
  • 【前端 DevOps】GitHub Actions 与 GitLab CI 实战:实现前端项目的自动化测试与部署
  • 2.【BUUCTF】bestphp‘s revenge
  • .NET-随机数Random(.NET 8)
  • 计算机毕业设计SpringBoot+Vue.js医院住院管理系统(源码+lw文档+PPT+讲解视频)
  • 蓝桥杯备考:贪心算法之纪念品分组
  • Redis --- 使用 Pipeline 实现批处理操作
  • 昆明hph网站建设/关键词自动优化工具
  • 愿意合作做游戏的网站平台/seo网络推广专员招聘
  • 河南省网架公司/seo网络运营
  • 布吉商城网站建设基本流程/北海seo快速排名
  • 佛山微信网站建设多少钱/淘宝关键词怎么做排名靠前
  • 创建网站的基本流程/郑州品牌网站建设