1. shared_ptr内存模型
shared_ptr 包含了一个指向对象的指针和一个指向控制块的指针。每一个由 shared_ptr 管理的对象都有一个控制块,它除了包含强引用计数、弱引用计数之外,还包含了自定义删除器的副本和分配器的副本以及其他附加数据。
2. 尽量使用make_shared
优势
- 避免代码冗余。
- 可编写异常安全代码。
- 提升性能。make_shared 只会进行一次内存分配,该内存单块既保存了T类型对象又保存与其相关联的控制块。而普通方式直接使用 new 操作符,除了为T类型对象分配一次内存,还要为与其关联的控制块再进行一次内存分配。
局限性
- 不允许自定义删除器
- 自定义内存管理的类,如重载了 new 操作符和 delete 操作符,不建议使用make_shared。因为:重载operator new和operator delete时,往往用来分配和释放该类精确尺寸(sizeof(T))的内存块;而make_shared创建的shared_ptr,是一个自定义了分配器(std::allocate_shared)和删除器的智能指针,由allocate_shared分配的内存大小也不等于上述的尺寸,而是在此基础上加上控制块的大小;
- 内存延迟释放问题。控制块和托管对象在同一内存块上分配,控制块是由 shared_ptr 和 weak_ptr 共享的,因此两者共同管理着这个内存单块。当强引用计数为 0 时,托管对象被析构(即析构函数被调用),但内存块并未被回收,只有等到最后一个 weak_ptr 离开作用域时,弱引用也减为 0 才会释放这块内存块。原本强引用计数减为 0 时就可以释放的内存, 现在变为了强引用计数和弱引用计数都减为 0 时才能释放。
3. enable_shared_from_this模板类
当我们需要一个类对象返回本身并且该类使用了 shared_ptr 智能指针时,需要使用该模板类。当我们使用智能指针管理资源时,必须统一使用智能指针,而不能再某些地方使用智能指针,某些地方使用原始指针,否则不能保持智能指针的语义,从而产生各种错误。
#include <iostream>
#include <memory>
using namespace std;
class Test
{
public: