C++11智能指针

目录

  1. 1. std::auto_ptr
  2. 2. std::unique_ptr
  3. 3. std::shared_ptr

智能指针是使用RAII方法对普通指针进行的封装, 所以智能指针实质是对象, 行为表现是指针.

RAII, Resource Acquisition Is Initialization, 资源获取就是初始化. RAII是一种管理资源、避免泄漏的惯用法. 通常的做法是对于一个对象而言, 我们在构造函数的时候申请空间, 而在析构函数(在离开作用域时调用)的时候释放空间.

使用智能指针可以方便的管理堆内存, 避免使用普通指针容易导致的堆内存未释放或二次释放等问题.

C++智能指针在C++11前是std::auto_ptr, C++11后是std::shared_ptr/std::unique_ptr/std::weak_ptr, 使用它们需要包含头文件<memory>.

std::auto_ptr

std::auto_ptr是C++11前提供的智能指针, 但从C++11开始, std::auto_ptr开始被弃用, 被std::unique_ptr替代.

std::auto_ptr的问题在于允许隐式的所有权转让, 容易导致不易发现的各种错误, 比如空指针访问.

std::auto_ptr<std::string> ps1(new std::string("hello world"));
std::auto_ptr<std::string> ps2;
ps2 = ps1;
std::cout << ps1;

ps2 = ps1ps1的资源所有权已经释放, 不再指向任何内容, 后面再访问ps1相当于在访问一个空指针.

std::unique_ptr

std::uniqur_ptrstd::auto_ptr的基础上禁止了拷贝和赋值, 这样上述std::auto_ptr中的问题就不存在了, 因为在编译阶段就会报错.

另外, 容器不支持保存std::auto_ptr, 但可以支持保存std::uniqur_ptr.

std::uniqur_ptr是应该优先选用的智能指针.

std::shared_ptr

std::shared_ptr使用引用计数, 多个指针对象可以指向相同的内存. 每次std::shared_ptr的拷贝, 内部引用计数加1; 每次std::shared_ptr的析构, 内部引用计数减1; 当引用计数减为0时, 自动释放指向的内存. std::shared_ptr内部引用计数是线程安全的, 但指向内存不是, 所以多线程使用std::shared_ptr还是需要锁.

  • 注意不要使用同一个原始指针初始化多个std::shared_ptr, 否则会造成同一内存的二次释放
  • 注意避免循环引用,循环引用会导致堆内存无法正确释放,导致内存泄漏. 这是std::shared_ptr的最大的陷阱.
  • 另外, std::shared_ptr使用的引用计数是增加了内存消耗和复杂性的, 所以能用std::unique_ptr时建议不要使用std::shared_ptr.