C++ 智能指针:从裸指针缺陷到标准库实践

[作者的个人Gitee>🌟](友人A (friend-a188881041351) - Gitee.com)🌟

每日一言:“**🌸🌸存在是一场无尽的对话,我们既是提问者,也是答案。🔅🔅”


1. 裸指针的四大硬伤

问题典型代码后果
异常泄漏int* p=new int[1024]; DoSomething(); delete[] p;DoSomething() 抛异常 → delete[] 未执行 → 泄漏
忘记释放void f(){ int* p=new int; return; }函数早退 → 直接泄漏
重复释放delete p; delete p;未定义行为,多数平台崩溃
所有权模糊void f(int* p);调用方不知道是否该 delete,极易 double-delete 或泄漏

2. RAII:把“资源”变成“对象”

核心理念:资源在构造函数中获得,在析构函数中释放。
C++ 标准库已经帮你写好模板,只需选合适的智能指针即可。


3. 智能指针选型速查表

场景推荐指针关键属性注意
独占,不可拷贝unique_ptr<T>move-only默认 delete,可自定义 deleter
共享,可拷贝shared_ptr<T>引用计数注意循环引用 → 搭配 weak_ptr
观察,不拥有weak_ptr<T>不计数使用前须 .lock() 判空

4. 独占场景:unique_ptr

// 单对象
std::unique_ptr<Date> up = std::make_unique<Date>(2024, 9, 11);

// 数组
std::unique_ptr<Date[]> up_arr = std::make_unique<Date[]>(5);

// 自定义释放
auto del = [](FILE* fp){ fclose(fp); };
std::unique_ptr<FILE, decltype(del)> up_file(fopen("log.txt", "w"), del);

要点

  • 禁止拷贝,只能 std::move
  • 析构时自动 delete 或调用自定义 deleter
  • make_unique 异常安全且只进行一次内存分配

5. 共享场景:shared_ptr

auto sp1 = std::make_shared<Date>(2024, 9, 11);
std::shared_ptr<Date> sp2 = sp1;   // 引用计数 +1
assert(sp1.use_count() == 2);

// 自定义 deleter
std::shared_ptr<FILE> sp_file(fopen("cfg.json", "r"),
                              [](FILE* fp){ fclose(fp); });

线程安全

  • 引用计数本身原子化,多线程拷贝/析构安全
  • 指向对象本身的并发读写仍需外部加锁

6. 循环引用与 weak_ptr

struct Node {
    std::shared_ptr<Node> next;   // 导致循环引用
    std::weak_ptr<Node> prev;     // 打破循环
};

诊断步骤

  1. 两个 shared_ptr 互相引用 → 引用计数始终 ≥1
  2. 把“非拥有”一方换成 weak_ptr → 退出作用域时计数可归零 → 资源正确释放
  3. 访问前用 .lock() 提升为 shared_ptr,为空说明对象已析构

7. 删除器:让智能指针管理任何资源

资源类型示例删除器用法
new[]std::default_delete<T[]>unique_ptr<T[]> 已内置
fopenfcloseshared_ptr<FILE>(fp, fclose)
mallocfreeshared_ptr<void>(p, free)
复合资源lambda[](T* p){ custom_cleanup(p); }

8. 不可用的过时方案

  • auto_ptr:C++98 遗留,拷贝转移所有权,极易悬空;C++11 起已废弃
  • 裸指针 + 手工 delete:仅用于教学或底层库,业务代码禁止

9. 快速迁移清单

  1. 全局搜索 new / new[]
  2. 若对象生命周期唯一 → 替换为 unique_ptr / make_unique
  3. 若需多处共享 → 替换为 shared_ptr / make_shared
  4. 若存在双向引用 → 把“反向”指针改为 weak_ptr
  5. 单元测试跑一遍 Valgrind / ASan,确认 0 泄漏

10. 结论

裸指针的泄漏、重复释放、所有权不清等问题在异常路径下几乎无法靠人工保证。
unique_ptr 处理独占,shared_ptr+weak_ptr 处理共享,配合自定义删除器,可覆盖 99% 的动态资源管理需求,且默认异常安全。
从今天起,业务代码中禁用 delete,让智能指针成为默认选择。


ique_ptr 处理独占,shared_ptr+weak_ptr处理共享,配合自定义删除器,可覆盖 99% 的动态资源管理需求,且默认异常安全。 从今天起,业务代码中禁用delete`,让智能指针成为默认选择。


如有错误,恳请指出。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐