首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >《深入理解 C++ 智能指针:unique_ptr、shared_ptr 与 weak_ptr 全解析》

《深入理解 C++ 智能指针:unique_ptr、shared_ptr 与 weak_ptr 全解析》

原创
作者头像
用户11690575
发布2025-06-11 21:29:46
发布2025-06-11 21:29:46
79800
代码可运行
举报
运行总次数:0
代码可运行

一、引言

在传统 C++ 编程中,内存泄漏是一个常见的问题。智能指针的引入极大地简化了资源管理,尤其在 C++11 以后,unique_ptr、shared_ptr 和 weak_ptr 被标准化并广泛应用于现代 C++ 项目中。

本文将全面讲解三种智能指针的使用场景、内部机制、常见陷阱,并通过图示和代码示例帮助读者构建对智能指针的系统性理解。


二、智能指针概览

智能指针类型

所有权

引用计数

可拷贝性

自动释放

unique_ptr

唯一

shared_ptr

共享

weak_ptr

非拥有


三、unique_ptr —— 独占式智能指针

3.1 基本使用

代码语言:javascript
代码运行次数:0
运行
复制
cpp复制编辑#include<memory>

std::unique_ptr<int> ptr = std::make_unique<int>(10);
std::cout << *ptr << std::endl;

3.2 转移所有权

代码语言:javascript
代码运行次数:0
运行
复制
cpp复制编辑std::unique_ptr<int> ptr2 = std::move(ptr);

📌 图示(逻辑结构):

代码语言:javascript
代码运行次数:0
运行
复制
scss复制编辑ptr ───► [10]
        (转移后)
ptr (null)   ptr2 ───► [10]

3.3 自定义析构函数

代码语言:javascript
代码运行次数:0
运行
复制
cpp复制编辑structFileCloser {
    voidoperator()(FILE* f)const { fclose(f); }
};

std::unique_ptr<FILE, FileCloser> file(fopen("data.txt", "r"));

四、shared_ptr —— 引用计数型智能指针

4.1 基本用法

代码语言:javascript
代码运行次数:0
运行
复制
cpp复制编辑std::shared_ptr<int> p1 = std::make_shared<int>(5);
std::shared_ptr<int> p2 = p1; // 引用计数 +1

4.2 使用场景

  • 对象被多个地方共享;
  • 生命周期交叉复杂,如图结构或缓存池;

📌 引用计数图示:

代码语言:javascript
代码运行次数:0
运行
复制
scss复制编辑p1 ─────┐
        │
p2 ─────┘────► [int=5] (use_count=2)

4.3 使用 use_count() 与 unique()

代码语言:javascript
代码运行次数:0
运行
复制
cpp复制编辑std::cout << p1.use_count();  // 引用计数
std::cout << p1.unique();     // 是否为唯一引用

五、weak_ptr —— 防止循环引用

5.1 循环引用问题

代码语言:javascript
代码运行次数:0
运行
复制
cpp复制编辑structA;
structB;

structA {
    std::shared_ptr<B> b;
};

structB {
    std::shared_ptr<A> a;
};

👎 此时对象永不释放!

📌 引用计数环:

代码语言:javascript
代码运行次数:0
运行
复制
css复制编辑A ─► B ─► A ...

5.2 使用 weak_ptr 打破循环

代码语言:javascript
代码运行次数:0
运行
复制
cpp复制编辑structB {
    std::weak_ptr<A> a; // 不增加引用计数
};

5.3 锁定 weak_ptr

代码语言:javascript
代码运行次数:0
运行
复制
cpp复制编辑if (auto shared_a = b->a.lock()) {
    shared_a->doSomething();
}

六、智能指针在容器中的应用

代码语言:javascript
代码运行次数:0
运行
复制
cpp复制编辑std::vector<std::shared_ptr<MyObject>> objs;
objs.push_back(std::make_shared<MyObject>());

注意事项:

  • 容器析构时自动释放所有对象;
  • 避免智能指针的多层嵌套,如 std::shared_ptr<std::vector<...>>。

七、智能指针的内部实现机制(简要)

7.1 shared_ptr 的核心结构

代码语言:javascript
代码运行次数:0
运行
复制
txt复制编辑shared_ptr
   │
   ▼
ControlBlock ───► 引用计数(use_count)
             └──► 弱引用计数(weak_count)
             └──► 实际对象指针

7.2 为什么 shared_ptr 比 raw pointer 慢一点

  • 内部涉及引用计数的原子操作;
  • 存在线程安全策略(C++11 后);

八、常见陷阱与误用

8.1 将 stack 对象交给智能指针托管(❌)

代码语言:javascript
代码运行次数:0
运行
复制
cpp复制编辑int x = 5;
std::shared_ptr<int> p(&x); // 错误:x 会被释放两次

应改为:

代码语言:javascript
代码运行次数:0
运行
复制
cpp复制编辑auto p = std::make_shared<int>(5);

8.2 使用 shared_from_this 时未继承 std::enable_shared_from_this(❌)

代码语言:javascript
代码运行次数:0
运行
复制
cpp复制编辑classMyClass : public std::enable_shared_from_this<MyClass> {
    voidf() {
        auto self = shared_from_this(); // 正确获取当前 shared_ptr
    }
};

九、性能比较与推荐使用场景

使用场景

推荐智能指针

独占资源、无共享

unique_ptr

多个对象共享所有权

shared_ptr

弱引用、观察者模式

weak_ptr

原始指针无所有权需求

原始指针(只读)

建议优先使用顺序:

代码语言:javascript
代码运行次数:0
运行
复制
cpp复制编辑unique_ptr > shared_ptr > raw pointer > weak_ptr(观察者/缓存)

十、智能指针项目实战:模拟游戏场景的资源管理

10.1 目标

创建角色类 Player 和装备类 Weapon,使用智能指针管理内存与生命周期。

10.2 类定义示例

代码语言:javascript
代码运行次数:0
运行
复制
cpp复制编辑classWeapon {
public:
    Weapon(std::string name) : name(name) {}
    ~Weapon() { std::cout << "Weapon destroyed\n"; }

private:
    std::string name;
};

classPlayer {
public:
    std::shared_ptr<Weapon> weapon;
};

10.3 使用示例

代码语言:javascript
代码运行次数:0
运行
复制
cpp复制编辑intmain() {
    auto sword = std::make_shared<Weapon>("Excalibur");
    Player p1, p2;
    p1.weapon = sword;
    p2.weapon = sword;

    std::cout << "Use count: " << sword.use_count() << "\n";
}

十一、结语

智能指针是现代 C++ 编程中不可或缺的工具。掌握其用法不仅可以避免内存泄漏,更是实现高质量代码的基础。开发者应根据场景选择最合适的指针类型,避免过度使用 shared_ptr,在设计阶段就思考生命周期与所有权关系。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 二、智能指针概览
  • 三、unique_ptr —— 独占式智能指针
    • 3.1 基本使用
    • 3.2 转移所有权
    • 3.3 自定义析构函数
  • 四、shared_ptr —— 引用计数型智能指针
    • 4.1 基本用法
    • 4.2 使用场景
    • 4.3 使用 use_count() 与 unique()
  • 五、weak_ptr —— 防止循环引用
    • 5.1 循环引用问题
    • 5.2 使用 weak_ptr 打破循环
    • 5.3 锁定 weak_ptr
  • 六、智能指针在容器中的应用
  • 七、智能指针的内部实现机制(简要)
    • 7.1 shared_ptr 的核心结构
    • 7.2 为什么 shared_ptr 比 raw pointer 慢一点
  • 八、常见陷阱与误用
    • 8.1 将 stack 对象交给智能指针托管(❌)
    • 8.2 使用 shared_from_this 时未继承 std::enable_shared_from_this(❌)
  • 九、性能比较与推荐使用场景
    • 建议优先使用顺序:
  • 十、智能指针项目实战:模拟游戏场景的资源管理
    • 10.1 目标
    • 10.2 类定义示例
    • 10.3 使用示例
  • 十一、结语
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档