智能指针
1.智能指针的分类
shared_ptr 允许多个指针指向同一个对象
unique_ptr 只允许唯一指针指向指定对象
weak_ptr 弱引用,指向 shared_ptr 所管理的对象
智能指针都定义在 memory 头文件中
2.shared_ptr
shared_ptr 是模板,创建时,必须提供指针指向的类型:
shared_ptr<string> p1; // shared_ptr 可以指向string
shared_ptr<list<int>> p2; // shared_ptr 可以指向 int 的 list
默认初始化的智能指针中保存着一个空指针
3.make_shared 函数
shared_ptr<int> p3 = make_shared<int>(42); // 指向一个值为 42 的 int 的shared_ptr
shared_ptr<string> p4 = make_shared<string>(5, 's'); // 指向一个值为 “sssss” 的 string
shared_ptr<int> p5 = make_shared<int>(); // 指向一个值为 0 的 int
auto p6 = make_shared<vector<string>>(); // 指向一个动态分配的空 vector<string>
4.shared_ptr 拷贝和赋值
auto p7 = make_shared<int>(2); // p7 指向的对象只有 p7 一个引用者
auto p8(p7); // p7 和 p8 指向相同的对象,此对象有两个引用者
引用计数:无论何时我们拷贝一个 shared_ptr,计数器都会递增,shared_ptr 赋予一个新值或被销毁,计数器就会递减。一旦一个 shared_ptr 计数器变为 0,它就会自动释放自己所管理的对象
5.shared_ptr 和 new 结合使用
shared_ptr<int> p9(new int(1024)); // 指向一个值为1024的 int
尽量使用 make_shared 而不使用 new
6.定义和改变 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(q, d) // 若 p 是唯一指向其对象的 shared_ptr, reset 会释放此对象, 若传递了可选的参数内置指针 q,会令 p 指向 q,否则会将 p 置为空,若还传递了参数 d,将会调用删除器 d 而不是 delete 来释放 q,reset 通常和 unique 一起使用
7.不要混合使用普通指针和智能指针
当将一个 shared_ptr 绑定到一个普通指针时,就不要再使用普通指针来访问 shared_ptr 所指向的内存了,也不要用 get 初始化另一个智能指针或为智能指针赋值
8.智能指针使用原则
不使用相同的内置指针初始化或 reset 多个智能指针
不 delete get() 返回的指针
不使用 get() 初始化或 reset 另一个智能指针
如果使用 get() 返回的指针, 记住当最后一个对应的智能指针销毁后,该内置指针就已经变为无效
如果使用智能指针管理的资源不是 new 分配的内存,记住传递给它一个删除器
9.unique_ptr
某个时刻只能有一个 unique 指向一个给定的对象,当 unique_ptr 被销毁时,它所指向的对象也被销毁
make_shared 不能返回 unique_ptr ,所以定义 unique_ptr 时,需要将其绑定到一个 new 返回的指针上
unique_ptr<int> p(new int(42)); // 指向一个值为42的int
unique_ptr 不支持普通的拷贝或赋值操作
unique_ptr<T, D> u(d); // 空 unique_ptr ,指向 T 类型的对象,用类型为 D 的对象代替 delete
u = nullptr; // 释放 u 指向的对象,将 u 置空
u.release(); // u 放弃对指针的控制权,返回指针,并将 u 置空
u.reset(); // 释放 u 指向的对象
u.reset(q); // 如果提供了内置指针 q, 令 u 指向这个对象,否则将 u 置空
u.reset(nullptr);
unique_ptr 虽然不能拷贝或赋值,但可以通过用 release 或 reset 将指针所有权从一个(非 const ) unique_ptr 转移给另一个 unique_ptr
unique_ptr<string> p2(p1.release());
unique_ptr<string> p3(new string("Text"));
p2.reset(p3.(release()));
如果不用另外一个智能指针来保存 release 返回的指针,就要程序员自己负责资源释放
不能拷贝 unique_ptr 的规则有一个例外,可以拷贝或赋值一个将要被销毁的unique_ptr,最常见的例子时从函数返回一个 unique_ptr
10.auto_ptr
早期版有 auto_ptr 类,具有一部分 unique_ptr 的特性,但不能在容器中保存 auto_ptr,也不能从函数返回 auto_ptr,虽然 auto_ptr 仍是标准库的一部分,但编程时应使用 unique_ptr
11.向 unique_ptr 传递删除器
重载一个 unique_ptr 中的删除器会影响到 unique_ptr 类型以及如何构造(或 reset) 该类型的对象,重载时,必须要在尖括号中指向的类型之后提供删除器类型,在创建或 reset 一个这种 unique_ptr 类型的对象时,必须提供一个指定类型的可调用对象(删除器)
unique_ptr<objT, delT> p (new objT, fun);
12.weak_ptr
weak_ptr 是一种不控制所指向对象生存周期的智能指针,它指向由一个 shared_ptr 管理的对象,将一个weak_ptr 绑定到一个 shared_ptr 不会改变 shared_ptr 的引用计数,一旦 shared_ptr 被销毁,即使 有weak_ptr 指向对象,对象也还是会被释放
创建一个 weak_ptr 时,要用一个 shared_ptr 来初始化它
auto p = make_shared<int> (42);
weak_ptr<int> wp(p);
如果不能确定对象是否存在,不能用 weak_ptr 直接访问对象, 必须调用lock(),此函数检查 weak_ptr 指向的对象是否存在,如果存在,返回一个指向共享对象的 shared_ptr,如果不存在,返回一个空的 shared_ptr