智能指针的实现原理是什么

15 分钟阅读 1169 字 + 1326 词
智能指针是利用 RAII机制 来保证资源的自动释放,从而 避免内存泄漏 unique_ptr shared_ptr 都是通过 析构函数 来管理资源的释放。当 unique_ptr 超出作用域时,会自动 调用删除操作符 来释放其指向的内存。
std::unique_ptr 通过 删除复制构造函数和复制赋值运算符来确保所有权的唯一性 ,但 提供移动构造函数和移动赋值运算符 ,允许所有权的转移。
shared_ptr 维护 一个指向原始对象的指针 一个指向控制块的指针 ,这个控制块通常包含 强弱引用计数 删除器,分配器 。每当创建一个新的 shared_ptr 或将一个 shared_ptr 赋值给另一个时,引用计数增加。当 shared_ptr 被销毁或通过标准库提供的 reset 成员函数重置时,引用计数减少。当 引用计数降到零时,控制块会释放资源并自我销毁 std::weak_ptr 是一种 不拥有对象 的智能指针,它 观察 std::shared_ptr 管理的对象,但 不增加引用计数 。它用于 解决 std::shared_ptr 之间可能产生的 循环引用问题 ,因为循环引用会导致引用计数永远不会达到零,从而造成内存泄漏。`
对于引用计数这一变量的存储,是在堆上的,多个shared_ptr的对象都指向同一个堆地址。
为什么尽量使用 make_shared ,make_shared只分配一次内存,通过指针构造shared_ptr有两次分配。当你使用 std::make_shared 时,这两个步骤被合并为一个原子操作, 进行一次内存分配,分配包括对象和控制块的连续内存 。如果使用先new,再传递给shared_ptr的构造函数时,本来new给对象分配了一个空间,然后构造shared_ptr的控制块又分配了一次空间。
智能指针的应用:
自动管理内存分配,延续对象的生命周期,监测对象的存在
作为函数的返回值,函数内部分配了堆的资源,想在类外面使用,并能够在类外面得到正确的释放。
参考答案
  1. std::unique_ptr
    • unique_ptr 代表独占所有权的智能指针,同一时间只能有一个 unique_ptr 实例指向特定资源。
    • 它通过析构函数来管理资源的释放。当 unique_ptr 超出作用域时,会自动调用删除操作符来释放其指向的内存。
    • std::unique_ptr 通过 删除复制构造函数和复制赋值运算符来确保所有权的唯一性 ,但提供移动构造函数和移动赋值运算符,允许所有权的转移。
  2. std::shared_ptr
    • shared_ptr 允许多个指针实例共享对同一资源的所有权,使用 引用计数机制 来跟踪有多少个 shared_ptr 指向同一资源。
    • 内部维护一个控制块,通常包含引用计数和资源的原始指针。每当创建一个新的 shared_ptr 或将一个 shared_ptr 赋值给另一个时,引用计数增加。
    • shared_ptr 被销毁或通过标准库提供的 reset 成员函数重置时,引用计数减少。当引用计数降到零时,控制块会释放资源并自我销毁。
  3. std::weak_ptr
    • std::weak_ptr 是一种不拥有对象的智能指针,它观察 std::shared_ptr 管理的对象,但不增加引用计数。
    • 它用于解决 std::shared_ptr 之间可能产生的循环引用问题,因为循环引用会导致引用计数永远不会达到零,从而造成内存泄漏。
总结
智能指针是利用 RAII机制 来保证资源的自动释放,从而 避免内存泄漏 unique_ptr shared_ptr 都是通过析构函数来管理资源的释放。当 unique_ptr 超出作用域时,会自动 调用删除操作符 来释放其指向的内存。 std::unique_ptr 通过 删除复制构造函数和复制赋值运算符来确保所有权的唯一性 ,但 提供移动构造函数和移动赋值运算符 ,允许所有权的转移。而 shared_ptr 维护一个控制块,通常包含 引用计数 和资源的原始指针。每当创建一个新的 shared_ptr 或将一个 shared_ptr 赋值给另一个时,引用计数增加。当 shared_ptr 被销毁或通过标准库提供的 reset 成员函数重置时,引用计数减少。当 引用计数降到零时,控制块会释放资源并自我销毁 std::weak_ptr 是一种 不拥有对象 的智能指针,它 观察 std::shared_ptr 管理的对象,但 不增加引用计数 。它用于 解决 std::shared_ptr 之间可能产生的 循环引用问题 ,因为循环引用会导致引用计数永远不会达到零,从而造成内存泄漏。`