C++智能指针详解与应用

发布时间:2026/7/2 11:17:00
C++智能指针详解与应用 C智能指针是用于自动化管理动态内存的RAIIResource Acquisition Is Initialization封装类核心目标是防止内存泄漏和空悬指针。标准库主要提供std::unique_ptr、std::shared_ptr和std::weak_ptr三种智能指针。核心智能指针对比特性std::unique_ptrstd::shared_ptrstd::weak_ptr所有权独占所有权不可拷贝可移动共享所有权使用引用计数弱引用不增加引用计数不拥有所有权拷贝/移动禁止拷贝允许移动允许拷贝和移动允许拷贝和移动主要用途管理独占资源替代auto_ptr管理多个指针共享的资源解决shared_ptr循环引用问题作为观察者性能开销近乎零开销与裸指针相当引用计数操作带来额外开销引用计数操作带来额外开销线程安全自身线程安全但管理的资源访问需额外同步引用计数原子操作线程安全但管理的资源访问需额外同步同shared_ptr使用方法与代码示例1.std::unique_ptr独占资源所有权离开作用域时自动释放内存。#include memory #include iostream // 1. 创建 unique_ptr std::unique_ptrint u1(new int(42)); // 传统方式 auto u2 std::make_uniqueint(100); // C14 推荐方式更安全高效 // 2. 访问资源 std::cout *u1 std::endl; // 输出: 42 u1.get(); // 获取裸指针// 3. 转移所有权移动语义 std::unique_ptrint u3 std::move(u1); // u1 变为 nullptr所有权转移给 u3 // 4. 自定义删除器例如用于文件句柄 struct FileDeleter { void operator()(FILE* fp) const { if (fp) fclose(fp); std::cout File closed. std::endl; } }; std::unique_ptrFILE, FileDeleter upFile(fopen(test.txt, r));2.std::shared_ptr通过引用计数实现共享所有权当最后一个shared_ptr离开作用域时释放资源。#include memory #include iostream // 1. 创建 shared_ptr auto s1 std::make_sharedint(200); //推荐方式一次内存分配同时容纳引用计数和对象 std::shared_ptrint s2(new int(300)); // 不推荐可能引发内存泄漏如果后续操作抛出异常 // 2. 拷贝与引用计数 auto s3 s1; //拷贝引用计数1 std::cout s1.use_count() std::endl; // 输出当前引用计数例如 2 // 3. 自定义删除器 std::shared_ptrint s4(new int[10], [](int* p) { delete[] p; }); // 正确管理数组 // 4. 典型应用共享资源 class Resource { public: Resource() { std::cout Resource acquired. ; } ~Resource() { std::cout Resource released. ; } void doSomething() { std::cout Doing something. ; } }; void process(std::shared_ptrResource res) { res-doSomething(); // 函数结束res 析构但引用计数不为0资源不释放 } int main() { auto mainRes std::make_sharedResource(); // 引用计数1 process(mainRes); // 传入时拷贝引用计数2函数返回后引用计数恢复为1 // main 结束mainRes 析构引用计数归0资源释放 return 0; }3.std::weak_ptr弱引用用于打破shared_ptr的循环引用避免内存泄漏。#include memory #include iostream class B; // 前向声明 class A { public: std::shared_ptrB bPtr; ~A() { std::cout A destroyed. ; } }; class B { public: // 关键使用 weak_ptr 而非 shared_ptr 来避免循环引用 std::weak_ptrA aWeakPtr; ~B() { std::cout B destroyed. ; } }; void testCycle() { auto a std::make_sharedA(); auto b std::make_sharedB(); a-bPtr b; // A 强引用 B b-aWeakPtr a; // B 弱引用 A不增加 A 的引用计数 // 离开作用域a 的引用计数从1变为0A 被销毁。 // A 销毁导致其成员 bPtr 析构B 的引用计数从1变为0B 也被销毁。 // 若 B 中使用 shared_ptr 指向 A则两者引用计数永不为0导致内存泄漏。 } int main() { testCycle(); // 正常输出 A destroyed. 和 B destroyed. return 0; } // weak_ptr 的基本操作 auto sp std::make_sharedint(88); std::weak_ptrint wp sp; // 创建 weak_ptr不增加引用计数 if (auto locked wp.lock()) { // 尝试提升为 shared_ptr std::cout *locked std::endl; // 提升成功资源仍存在 } else { std::cout Object has been destroyed. ; // 提升失败资源已释放 }核心原理RAII 与引用计数智能指针基于RAII思想资源在构造函数中获取在析构函数中自动释放确保异常安全。shared_ptr内部维护一个控制块其中包含引用计数、弱引用计数和删除器等。每次拷贝构造或赋值引用计数递增每次析构引用计数递减归零时调用删除器释放资源。选择指南与最佳实践默认选择std::unique_ptr除非需要共享所有权否则优先使用unique_ptr因其开销最小且语义明确。需共享时使用std::shared_ptr当多个对象需要共同管理同一资源的生命周期时使用。打破循环引用使用std::weak_ptr当存在shared_ptr相互引用或需要观察但不拥有资源时使用。优先使用make_shared和make_unique它们提供更强的异常安全性且对于make_shared能将对象和控制块分配在连续内存中提升效率。避免裸指针与智能指针混用不要将同一块原生内存交给多个独立的智能指针管理会导致重复释放。注意线程安全智能指针本身的引用计数操作是原子的但其所指向数据的读写仍需用户自行同步。参考来源C 智能指针详细介绍底层原理、使用方法和应用场景C中智能指针的设计和使用智能指针--C【C】智能指针的使用及其原理cpp智能指针的原理与使用