《C++11:智能指针》

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

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

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


文章目录

  • [C++ 智能指针:从裸指针缺陷到标准库实践](#C++ 智能指针:从裸指针缺陷到标准库实践)
    • [1. 裸指针的四大硬伤](#1. 裸指针的四大硬伤)
    • [2. RAII:把"资源"变成"对象"](#2. RAII:把“资源”变成“对象”)
    • [3. 智能指针选型速查表](#3. 智能指针选型速查表)
    • [4. 独占场景:unique_ptr](#4. 独占场景:unique_ptr)
    • [5. 共享场景:shared_ptr](#5. 共享场景:shared_ptr)
    • [6. 循环引用与 weak_ptr](#6. 循环引用与 weak_ptr)
    • [7. 删除器:让智能指针管理任何资源](#7. 删除器:让智能指针管理任何资源)
    • [8. 不可用的过时方案](#8. 不可用的过时方案)
    • [9. 快速迁移清单](#9. 快速迁移清单)
    • [10. 结论](#10. 结论)

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

cpp 复制代码
// 单对象
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

cpp 复制代码
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

cpp 复制代码
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[]> 已内置
fopen fclose shared_ptr<FILE>(fp, fclose)
malloc free shared_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`,让智能指针成为默认选择。


如有错误,恳请指出。

相关推荐
qq_1927798713 小时前
C++模块化编程指南
开发语言·c++·算法
代码村新手14 小时前
C++-String
开发语言·c++
历程里程碑15 小时前
滑动窗口---- 无重复字符的最长子串
java·数据结构·c++·python·算法·leetcode·django
2501_9403152616 小时前
航电oj:首字母变大写
开发语言·c++·算法
lhxcc_fly17 小时前
手撕简易版的智能指针
c++·智能指针实现
浒畔居17 小时前
泛型编程与STL设计思想
开发语言·c++·算法
Fcy64817 小时前
C++ 异常详解
开发语言·c++·异常
机器视觉知识推荐、就业指导17 小时前
Qt 和 C++,是不是应该叫 Q++ 了?
开发语言·c++·qt
liu****17 小时前
三.Qt图形界面开发完全指南:从入门到掌握常用控件
开发语言·c++·qt
小龙报18 小时前
【C语言进阶数据结构与算法】单链表综合练习:1.删除链表中等于给定值 val 的所有节点 2.反转链表 3.链表中间节点
c语言·开发语言·数据结构·c++·算法·链表·visual studio