C++之智能指针

-
-
2026-07-06 15:59

本文内容为《C++ Primer(第五版)》相关章节整理而得。

  • 为了更容易。更安全的使用动态内存,新的标准库提供了以下智能指针类型来管理动态对象,它的行为与常规指针类似,重要的区别是它负责自动释放所指向的类型。
    • shared_ptr:允许多个指针指向同一个对象。
    • unique_ptr:独占所指向的对象。
    • weak_ptr:弱引用,指向shared_ptr所管理的对象。
  • 这三种类型都定义在memory头文件中。
  • 在早期C++中,还有一个auto_ptr智能指针,在C++98中引入,由于有缺陷,在C++11中被标记为弃用,在C++17中彻底移除,官方建议用unique_ptr替代。

一、shared_ptr类

1. 定义

创建一个智能指针时,必须提供指针可以指向的类型,例如:

shared_ptr<string> p1; /// 指向string
shared_ptr<list<int>> p2; /// 指向int的list

默认初始化的智能指针中保存着一个空指针。

2. 智能指针支持的操作

操作解释适用指针
shared_ptr<T> sp空智能指针,指向类型为T的对象 
unique_ptr<T> up 
p将p用作一个条件判断,若p指向一个对象,则为true两个指针都适用
*p解引用指针,获得所指向对象
p→mem等价于(*p).mem
p.get()返回p中保存的指针,若智能指针释放了其对象,返回的指针所指向的对象也就消失了。
swap(p,q)交换p和q中的指针
p.swap(q)
make_shared<T>(args)返回一个shared_ptr,指向一个动态分配的类型为T的对象。使用args初始化此对象。shared_ptr独有
shared_ptr<T>p (q)p是shared_ptr的拷贝,此操作会递增q中的计数器,q中的指针必须能转换为T*
p = qp和q都是shared_ptr,所保存的指针必须能相互转换。此操作会递减p的引用计数,递增q的引用计数;若p的引用计数变为0,则将其管理的原内存释放。
p.unique()若p.use_count()为1,返回true,否则返回false。
p.use_count()返回与p共享对象的智能指针数量,可能很慢,主要用于调试。

3. make_shared函数

  • 这是最安全的分配和使用动态内存的方法,次函数在动态内存中分配一个对象并初始化它,但会指向此对象的shared_ptr
  • 定义在头文件memory中。
shared_ptr<int> p3 = make_shared<int>(42); /// 指向一个值为42的int的shared_ptr
shared_ptr<int> p4 = make_shared<int>(); /// 值默认为0
  • 如果不传递任何参数,则对象会进行值初始化。

4. shared_ptr的拷贝和赋值

  • 当进行拷贝或赋值操作时,每个shared_ptr都会记录有多少个其他shared_ptr指向相同的对象,例如:

    auto p = make_shared<int>(42); /// p指向的对象只有p一个引用者。
    auto q(p);	/// p和q指向相同的对象,此对象有两个引用者。
  • 引用计数:每个shared_ptr都有一个关联的计数器。
    • shared_ptr被拷贝时,计数器递增。
    • shared_ptr被赋予新值或者销毁时,计数器递减。
    • 当计数器为0时,释放所管理对象。

5. 定义和改变shared_ptr的其他方法

操作解释
shared_ptr<T> p(q)p管理内置指针q所指向的对象,q必须指向new分配的内存,且能够转换为T*类型。
shared_ptr<T> p(u)p从unique_ptr u接管了对象的所有权,将u置为空
shared_ptr<T> p(q, d)p接管了内置指针q所指向的对象的所有权。q必须能转换为T*类型。p将使用可调用对象d来代替delete
shared_ptr<T> p(p2, d)p是shared_ptr p2的拷贝,区别是p将用可调用对象d来代替delete
p.reset()若p是唯一指向其对象的shared_ptr,reset会释放此对象。若传递了可选的参数内置指针q,会令p指向q,否则会将p置为空。若还传递了参数d,将会调用d而不是delete来释放q。
p.reset(q)
p.reset(q, d)

6. 智能指针使用基本规范

  • 不要混合使用智能指针和普通指针。
  • 不使用相同的内置指针初始化(或reset)多个智能指针
  • 不delete get()返回的指针。
  • 不使用get()初始化或reset另一个智能指针。
  • 如果使用get()返回的指针,记住当最后一个对应的智能指针销毁后,所返回的指针就变为无效了。
  • 如果使用智能指针管理的资源不是new分配的内存,需要传递给它一个删除器。

二、unique_ptr类

  • 一个unique_ptr拥有它所指向的对象,与shared_ptr不用,某个时刻只能有一个unique_ptr指向一个给定对象。

1. 定义

  • shared_ptr不同,没有类似make_shared的标准库函数来返回一个unique_ptr,定义一个unique_ptr时,需将其绑定到一个new 返回的指针上,且初始化unique_ptr时必须采用直接值初始化形式:

    unique_ptr<double> p1; /// 可以指向一个double的unique_ptr
    unique_ptr<int> p2(new int(42)); /// p2指向一个值为42的int
  • 由于一个unique_ptr拥有它所指向的对象,因此它不支持普通的拷贝或赋值操作。

2. unique_ptr支持的操作

  • 除了第一节第2点中介绍的智能指针都支持的操作之外,unique_ptr还支持下列操作:
操作解释
unique_ptr<T> u1空unique_ptr,可以指向类型为T的对象。u1会使用delete来释放它的指针,u2会使用一个类型为D的可调用对象来释放它的指针。
unique_ptr<T, D> u2
unique_ptr<T, D> u(d)空unique_ptr,指向类型为T的对象,用类型D的对象代替delete。
u = nullptr释放u指向的对象,将u置空。
u.release()u放弃对指针的控制权,返回指针,并将u置空。
u.reset()释放u指向的对象,如果提供了内置指针q,则令u指向q。否则将u置空。
u.reset(q)
u.reset(nullptr)
  • 虽然不能拷贝或者赋值unique_ptr,但可以通过调用releasereset将指针的所有权从一个(非const)unique_ptr转移给另一个unique_ptr

三、weak_ptr类

weak_ptr是一种不控制所指向对象生存期的智能指针,它指向一个由shared_ptr管理的对象,将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。

1. 定义

auto p = make_shared<int>(42);
weak_ptr<int> wp(p); /// wp弱共享p,p的引用计数未改变。
  • 由于对象可能不存在,因此不能使用weak_ptr直接访问对象,而必须调用lock

    if (shared_ptr<int> np = wp.lock()) {} /// 如果np不为空则条件成立

2. weak_ptr支持的操作

操作解释
weak_ptr<T> w空weak_ptr可以指向类型为T的对象
weak_ptr<T> w(sp)与shared_ptr sp指向相同对象的weak_ptr。T必须能转换为sp指向的类型。
w = pp可以是一个shared_ptr或一个weak_ptr。赋值后w与p共享对象。
w.reset()将w置为空。
w.use_count()与w共享对象的shared_ptr的数量
w.expired()若w.use_count()为0,则返回true,否则返回false
w.lock()如果expired为true,返回一个空shared_ptr,否则返回一个指向w的对象的shared_ptr

 


目录