智能指针核心是用RAII自动管理堆内存,避免裸指针的内存泄漏与崩溃;引用计数需独立分配内存并原子操作;拷贝/赋值需同步更新计数;重载*、->等运算符以支持指针式访问。

智能指针核心要解决什么问题
裸指针容易忘 delete、重复 delete、提前释放,导致内存泄漏或崩溃。手写智能指针本质是用对象生命周期(构造/析构)自动管理堆内存——这就是 RAII(Resource Acquisition Is Initialization)。关键不在“指针像指针”,而在“析构时自动释放资源”。
引用计数怎么存才安全
引用计数不能和托管对象混在一起(否则 new T 无法带计数),也不能单独 new 一个 int(多一次分配,且难保证线程安全)。主流做法是额外分配一块内存,把计数和指针一起存:
- 用 new char[sizeof(size_t) + sizeof(T*)] 分配原始内存
- 用 placement new 在前 sizeof(size_t) 字节放引用计数,在后放 T* 指针
- 析构时先调用 T 的析构函数,再释放整块内存
这样只做一次堆分配,缓存友好,也方便原子操作(比如用 std::atomic_size_t 存计数)。
拷贝和赋值必须同步更新计数
拷贝构造函数和 operator= 不是简单复制指针,而是:增加原对象的引用计数,让新对象共享同一份资源;同时原对象析构或重置时,要递减计数,仅当计数归零才真正 delete。
立即学习“C++免费学习笔记(深入)”;
- 拷贝构造:++count,ptr = other.ptr
- 赋值:先对当前对象做“减一并可能 delete”,再 ++other.count,更新 ptr
- reset():减一并可能 delete,再 new 新对象、计数设为 1
注意 operator= 要自赋值安全(检查 this == &other)。
解引用和成员访问要像原生指针
重载 * 和 -> 是必须的:
- * 返回 *ptr(不是 ptr 的拷贝,是引用)
- -> 返回 ptr(让 ptr->func() 可用)
- 还建议重载 get() 返回原始指针,use_count() 查看计数,operator bool() 支持 if (sp) 判断是否非空
别忘了 const 版本:const T* get() const,T& operator*() const 等,否则 const 对象无法解引用。
基本上就这些。RAII 是骨架,引用计数是血肉,而 operator 重载是让它“用起来像指针”的最后一层封装。不复杂但容易忽略细节,比如计数初始化、析构顺序、线程安全边界——生产环境推荐 std::shared_ptr,但手写一遍能真正看清内存管理的因果链。









