目录一、开篇为什么需要 shared_ptr二、shared_ptr 核心原理引用计数三、shared_ptr 基础用法四、shared_ptr 核心坑点五、总结一、开篇为什么需要 shared_ptrunique_ptr解决了 “独占式内存管理”但实际开发中经常需要多个指针共享同一块内存比如容器中存储指针、多模块共享资源。这时候shared_ptr就派上用场了 —— 它通过引用计数实现 “共享所有权”让内存管理更灵活。二、shared_ptr 核心原理引用计数通俗解释shared_ptr内部维护一个 “计数器”记录有多少个shared_ptr指向同一块内存新shared_ptr拷贝时计数器 1shared_ptr销毁 / 重置时计数器 -1计数器为 0 时自动释放内存。三、shared_ptr 基础用法1. 基本创建与引用计数#include iostream #include memory using namespace std; class Person { public: string name; int age; Person(string n, int a) : name(n), age(a) { cout name Person() endl; } ~Person() { cout name ~Person() endl; } }; int main() { // 方式1推荐make_shared更高效一次分配内存 shared_ptrPerson p1 make_sharedPerson(张三, 20); cout 引用计数 p1.use_count() endl; // 1 // 拷贝引用计数1 shared_ptrPerson p2 p1; cout 引用计数 p1.use_count() endl; // 2 // 重置 p1引用计数-1 p1.reset(); cout 引用计数 p2.use_count() endl; // 1 return 0; // p2 析构引用计数0释放内存 }make_shared比new更高效new会分两次分配内存对象 引用计数make_shared一次分配。2. 管理数组C17 前后差异int main() { // C17 前需要自定义删除器默认用 delete数组需要 delete[] shared_ptrint arr1(new int[4], [](int* p) { delete[] p; }); for (int i 0; i 4; i) { arr1.get()[i] i 10; // get() 获取裸指针 cout arr1.get()[i] ; // 10 11 12 13 } cout endl; // C17原生支持数组 shared_ptrint[] arr2 make_sharedint[](4); for (int i 0; i 4; i) { arr2[i] i 20; cout arr2[i] ; // 20 21 22 23 } cout endl; return 0; }get()获取底层裸指针仅用于访问不要手动释放自定义删除器解决shared_ptr对数组的兼容问题。四、shared_ptr 核心坑点1. 循环引用内存泄漏重灾区#include iostream #include memory using namespace std; // 循环引用示例内存泄漏 class B; class A { public: shared_ptrB b_ptr; // 共享引用 B ~A() { cout ~A() endl; } }; class B { public: shared_ptrA a_ptr; // 共享引用 A ~B() { cout ~B() endl; } }; int main() { shared_ptrA a make_sharedA(); shared_ptrB b make_sharedB(); a-b_ptr b; b-a_ptr a; // 引用计数a2b2 → 析构后计数1内存泄漏 return 0; }a引用bb引用a两者引用计数都是 2函数结束后a/b析构计数变为 1永远不会为 0 → 内存泄漏临时解决方案weak_ptr彻底解决2. 用裸指针创建多个 shared_ptr重复释放int main() { Person* raw_ptr new Person(李四, 25); shared_ptrPerson p1(raw_ptr); shared_ptrPerson p2(raw_ptr); // 错误两个 shared_ptr 管理同一裸指针 return 0; // 析构时重复释放程序崩溃 }解决方案始终用make_shared或仅用一个shared_ptr接管裸指针。五、总结shared_ptr是 “灵活但易踩坑” 的智能指针核心是引用计数支持多指针共享内存优先用make_shared提升效率最大坑是循环引用需配合weak_ptr解决非必要不使用避免额外开销。
C++ shared_ptr 深度解析:共享式智能指针的原理与坑
目录一、开篇为什么需要 shared_ptr二、shared_ptr 核心原理引用计数三、shared_ptr 基础用法四、shared_ptr 核心坑点五、总结一、开篇为什么需要 shared_ptrunique_ptr解决了 “独占式内存管理”但实际开发中经常需要多个指针共享同一块内存比如容器中存储指针、多模块共享资源。这时候shared_ptr就派上用场了 —— 它通过引用计数实现 “共享所有权”让内存管理更灵活。二、shared_ptr 核心原理引用计数通俗解释shared_ptr内部维护一个 “计数器”记录有多少个shared_ptr指向同一块内存新shared_ptr拷贝时计数器 1shared_ptr销毁 / 重置时计数器 -1计数器为 0 时自动释放内存。三、shared_ptr 基础用法1. 基本创建与引用计数#include iostream #include memory using namespace std; class Person { public: string name; int age; Person(string n, int a) : name(n), age(a) { cout name Person() endl; } ~Person() { cout name ~Person() endl; } }; int main() { // 方式1推荐make_shared更高效一次分配内存 shared_ptrPerson p1 make_sharedPerson(张三, 20); cout 引用计数 p1.use_count() endl; // 1 // 拷贝引用计数1 shared_ptrPerson p2 p1; cout 引用计数 p1.use_count() endl; // 2 // 重置 p1引用计数-1 p1.reset(); cout 引用计数 p2.use_count() endl; // 1 return 0; // p2 析构引用计数0释放内存 }make_shared比new更高效new会分两次分配内存对象 引用计数make_shared一次分配。2. 管理数组C17 前后差异int main() { // C17 前需要自定义删除器默认用 delete数组需要 delete[] shared_ptrint arr1(new int[4], [](int* p) { delete[] p; }); for (int i 0; i 4; i) { arr1.get()[i] i 10; // get() 获取裸指针 cout arr1.get()[i] ; // 10 11 12 13 } cout endl; // C17原生支持数组 shared_ptrint[] arr2 make_sharedint[](4); for (int i 0; i 4; i) { arr2[i] i 20; cout arr2[i] ; // 20 21 22 23 } cout endl; return 0; }get()获取底层裸指针仅用于访问不要手动释放自定义删除器解决shared_ptr对数组的兼容问题。四、shared_ptr 核心坑点1. 循环引用内存泄漏重灾区#include iostream #include memory using namespace std; // 循环引用示例内存泄漏 class B; class A { public: shared_ptrB b_ptr; // 共享引用 B ~A() { cout ~A() endl; } }; class B { public: shared_ptrA a_ptr; // 共享引用 A ~B() { cout ~B() endl; } }; int main() { shared_ptrA a make_sharedA(); shared_ptrB b make_sharedB(); a-b_ptr b; b-a_ptr a; // 引用计数a2b2 → 析构后计数1内存泄漏 return 0; }a引用bb引用a两者引用计数都是 2函数结束后a/b析构计数变为 1永远不会为 0 → 内存泄漏临时解决方案weak_ptr彻底解决2. 用裸指针创建多个 shared_ptr重复释放int main() { Person* raw_ptr new Person(李四, 25); shared_ptrPerson p1(raw_ptr); shared_ptrPerson p2(raw_ptr); // 错误两个 shared_ptr 管理同一裸指针 return 0; // 析构时重复释放程序崩溃 }解决方案始终用make_shared或仅用一个shared_ptr接管裸指针。五、总结shared_ptr是 “灵活但易踩坑” 的智能指针核心是引用计数支持多指针共享内存优先用make_shared提升效率最大坑是循环引用需配合weak_ptr解决非必要不使用避免额外开销。