跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

C++ 智能指针详解:原理、模拟实现与使用场景

C++ 智能指针基于 RAII 思想自动管理动态内存,解决手动 delete 导致的泄漏和重复释放问题。标准库提供 auto_ptr、unique_ptr、shared_ptr 和 weak_ptr。unique_ptr 独占所有权,shared_ptr 共享引用计数,weak_ptr 解决循环引用。通过自定义删除器可处理特殊内存分配。掌握智能指针是安全 C++ 开发的关键。

邪神洛基发布于 2026/3/27更新于 2026/5/3116 浏览
C++ 智能指针详解:原理、模拟实现与使用场景

C++ 智能指针详解

引言

在 C++ 编程中,动态内存管理始终是开发者面临的核心挑战之一。手动使用 new 分配内存、delete 释放内存的模式,不仅需要开发者时刻关注内存生命周期,更可能因疏忽导致内存泄漏(忘记调用 delete)、二次释放(重复调用 delete),或是在异常抛出时因执行流跳转跳过 delete 语句等问题。

为解决这一痛点,C++ 标准库引入了智能指针这一核心工具。它基于'资源获取即初始化'(RAII)的设计思想,将动态内存资源封装为对象的成员,利用 C++ 对象自动调用析构函数的特性,实现内存的'自动释放',从根本上减少手动管理内存的负担与风险。

本文将系统梳理智能指针的核心作用、实现原理,并针对 C++ 标准库中不同类型的智能指针展开详细解析,包括它们的设计逻辑、模拟实现代码、适用场景,以及如何规避典型问题。

智能指针的作用

作用:如果正确使用了智能指针的话,就不用自己手动 delete 了。

自己手动 delete 容易忽略的地方:在抛异常时容易跳过自己写的 delete 或者自己忘记 delete 了。

智能指针的实现和原理

原理:资源交给对象管理,对象生命周期内,资源有效;对象生命周期到了,释放资源——用的是 RAII 思想。

实现要求:让对象的用法像指针一样。

template <class T>
class SmartPtr {
public:
    SmartPtr(T* ptr) : _ptr(ptr) {}
    ~SmartPtr() { delete _ptr; }
    T& operator*() { return *_ptr; }
    T* operator->() { return _ptr; }
private:
    T* _ptr;
};

使用示例:

SmartPtr<string> sp(new string("renshen"));

这种基础智能指针有个问题:没有处理拷贝语义,可能导致双重释放。

标准库中的智能指针

不需要拷贝的场景,一般使用 unique_ptr。

需要拷贝的场景,一般使用 shared_ptr,但要小心循环引用。

std::auto_ptr

这是 C++98 实现的智能指针,原理是管理权的转移。在拷贝时,会把被拷贝对象的资源管理权转移给拷贝对象,被拷贝对象悬空。

这个智能指针有很大的弊端:如果管理权被转移了,之前那个指针就会变成空指针。因此很多公司明令禁止使用。

auto_ptr 的模拟实现
template <class T>
class auto_ptr {
public:
    auto_ptr(T* ptr) : _ptr(ptr) {}
    ~auto_ptr() { delete _ptr; }
    T& operator*() { return *_ptr; }
    T* operator->() { return _ptr; }
    
    // 拷贝构造函数,转移所有权
    auto_ptr(auto_ptr<T>& ap) : _ptr(ap._ptr) { 
        ap._ptr = nullptr; 
    }
    
    // 赋值运算符也会转移所有权
    auto_ptr& operator=(auto_ptr<T>& ap) {
        if (this != &ap) {
            delete _ptr;
            _ptr = ap._ptr;
            ap._ptr = nullptr;
        }
        return *this;
    }
private:
    T* _ptr;
};

std::unique_ptr

unique_ptr, shared_ptr 和 weak_ptr 是 Boost 库先实现的,后来 C++11 也支持这几个智能指针的使用了。

unique_ptr 直接让智能指针不能拷贝和赋值,且不支持管理权转移(除非显式移动)。这个智能指针也是基于 RAII 思想实现的。

unique_ptr 的模拟实现
template <class T>
class unique_ptr {
public:
    unique_ptr(T* ptr) : _ptr(ptr) {}
    ~unique_ptr() { delete _ptr; }
    T& operator*() { return *_ptr; }
    T* operator->() { return _ptr; }
    
    // 禁止拷贝
    unique_ptr(const unique_ptr<T>&) = delete;
    unique_ptr& operator=(const unique_ptr<T>&) = delete;
    
    // 允许移动
    unique_ptr(unique_ptr<T>&& other) noexcept : _ptr(other._ptr) {
        other._ptr = nullptr;
    }
    unique_ptr& operator=(unique_ptr<T>&& other) noexcept {
        if (this != &other) {
            delete _ptr;
            _ptr = other._ptr;
            other._ptr = nullptr;
        }
        return *this;
    }
private:
    T* _ptr;
};

引申:一般拷贝不让实现的话,赋值也不能实现。

std::shared_ptr

这个智能指针是最全面的,一般都是用的这个,然后有循环引用的时候搭配 weak_ptr 用。

原理:通过引用计数的方式来实现多个 shared_ptr 对象之间共享资源。

shared_ptr 的模拟实现
template <class T>
class shared_ptr {
public:
    shared_ptr(T* ptr = nullptr) : _ptr(ptr), _pcount(new int(1)) {}
    
    template <class D>
    shared_ptr(T* ptr, D del) : _ptr(ptr), _pcount(new int(1)), _del(del) {}
    
    ~shared_ptr() {
        if (--(*_pcount) == 0) {
            _del(_ptr);
            delete _pcount;
        }
    }
    
    T& operator*() { return *_ptr; }
    T* operator->() { return _ptr; }
    
    shared_ptr(const shared_ptr<T>& sp) : _ptr(sp._ptr), _pcount(sp._pcount) {
        ++(*_pcount);
    }
    
    shared_ptr<T>& operator=(const shared_ptr<T>& sp) {
        if (_ptr == sp._ptr) return *this;
        if (--(*_pcount) == 0) {
            _del(_ptr);
            delete _pcount;
        }
        _ptr = sp._ptr;
        _pcount = sp._pcount;
        ++(*_pcount);
        return *this;
    }
    
    T* get() const { return _ptr; }
private:
    T* _ptr;
    int* _pcount;
    function<void(T*)> _del = [](T* ptr){ delete ptr; };
};

用法:

shared_ptr<A> sp1(new A(1));

注意:shared_ptr<A> 跟 A 可不是一个类型。

编译器对越界访问的检查一般不是很彻底的。

shared_ptr 的一个弊端

shared_ptr 在遇到循环引用的时候也是会内存泄漏的。

std::weak_ptr

weak_ptr 这个智能指针不是 RAII 思想的,它的唯一作用就是解决 shared_ptr 的循环引用问题的。

这个智能指针可以访问资源,但是不参与资源释放的解决。

注意:weak_ptr 库里面实现了让它可以和 shared_ptr 相互转换。

weak_ptr 的模拟实现
template <class T>
class weak_ptr {
public:
    weak_ptr() : _ptr(nullptr) {}
    weak_ptr(const shared_ptr<T>& sp) : _ptr(sp.get()) {}
    
    weak_ptr<T>& operator=(const shared_ptr<T>& sp) {
        _ptr = sp.get();
        return *this;
    }
    
    T* get() const { return _ptr; }
private:
    T* _ptr;
};

删除定制器

在智能指针使用过程中,可能会有 new[] 或者 malloc 出来的空间,这些空间用 delete 根本不行,此时就需要删除定制器了。

库里面的话,是给 unique_ptr 和 shared_ptr 配备了删除定制器的。

这里的话,自己模拟实现一下 shared_ptr 的删除定制器(在上面的模拟实现里面已经写了)。

总结

掌握智能指针是安全 C++ 开发的关键。根据所有权需求选择 unique_ptr 或 shared_ptr,配合 weak_ptr 避免循环引用,并使用自定义删除器处理特殊内存分配,能有效杜绝内存泄漏。

目录

  1. C++ 智能指针详解
  2. 引言
  3. 智能指针的作用
  4. 智能指针的实现和原理
  5. 标准库中的智能指针
  6. std::auto_ptr
  7. auto_ptr 的模拟实现
  8. std::unique_ptr
  9. unique_ptr 的模拟实现
  10. std::shared_ptr
  11. shared_ptr 的模拟实现
  12. shared_ptr 的一个弊端
  13. std::weak_ptr
  14. weak_ptr 的模拟实现
  15. 删除定制器
  16. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Python 集合与列表性能对比:何时更快?
  • DeepSeek R1 671B 本地部署与动态量化技术详解
  • FPGA 开发常用软件对比:Vivado、Quartus、ModelSim 详解
  • C++ 原子操作 compare_exchange_weak 详解
  • Web 技术核心与安全风险(三):PHP 基础与数据交互
  • GitHub Copilot 学生认证指南
  • 手机端运行 Stable Diffusion 的开源方案与使用指南
  • MySQL Windows 环境安装与配置指南
  • C++ 工程师在 AIGC 模型加载中的技术挑战与解决方案
  • 圣女司幼幽-Z-Turbo 模型:10 分钟搭建牧神记 AI 绘画工作流
  • iFlow Cli:终端 AI 助手使用指南
  • 大模型 Token 与上下文窗口详解
  • 微信小程序接入 Gitee 进行版本管理与团队协作
  • Java ResourceBundle 与 .NET RESX 国际化方案对比
  • MySQL 权限管控与 C/C++ 客户端接入实战
  • GitHub 趋势日报 (2025 年 08 月 11 日)
  • 为何 glTF 与 GLB 格式成为标准化主资产的主流选择
  • Python 基础语法完全指南:变量、类型与运算符
  • ECJ 编译器安装配置与高效快捷键实战指南
  • Vue 组件 Prop 验证与枚举值最佳实践

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online