template <class T, class... Args>
shared_ptr<T> make_shared (Args&&... args);
std::shared_ptr<int> foo = std::make_shared<int> (10);
// same as:
std::shared_ptr<int> foo2 (new int(10));
auto bar = std::make_shared<int> (20);
auto baz = std::make_shared<std::pair<int,int>> (30,40);
shared_ptr<T> p(q) // p管理内置指针q所指向的对象;q必须指向new分配的内存,并且能够转换为T*类型
shared_ptr<T> p(q, d) // p接管了内置指针q所指向的对象;p将使用可调用对象d来代替delete
p.reset() // 若p是唯一指向其对象的shared_ptr,reset会释放此对象
p.get() // 返回p中保存的指针,若智能指针释放了其对象,返回的指针所指向的对象也就消失了
swap(p, q) // 交换p和q中的指针
p.swap(q)
shared_ptr<T>p(q) // 用q初始化p
p = q;
p.unique() // 若p.use_count()为1,返回true,否则返回false
p.use_count() // 返回与p共享对象的智能指针的数量,很慢,主要用于调试
shared_ptr可以使用不是new运算符产生的指针,只要有对应于析构所使用的deleter:
struct destination;
struct connection;
connection connect(destination *); // 建立连接
void disconnect(connection); // 断开连接
void fun(destination &d, ...) {
connection c = connect(&d);
// 使用连接
// 如果在fun退出前没有调用disconnect,就无法关闭c了
}
使用自定义的deleter:
void end_connection(connection *p) { disconnect(*p); }
重写fun():
void f(destination &d, ...) {
connection c = connect(&d);
shared_ptr<connection> p(&c, end_connection);
// 使用连接
// 即使fun由于异常退出,connection仍然能正常关闭
}
智能指针陷阱
- 不使用相同的内置指针初始化(或reset)多个智能指针
- 不要delete get()返回的内置指针
- 不要使用get()初始化或reset另一个智能指针
- 如果使用了get()返回的指针,记住当左后一个对应的智能指针销毁后,这个指针就变为无效了
- 如果使用智能指针管理的资源不是new分配的内存,记得要传递给它一个删除器deleter
unique_ptr<T> u1;
unique_ptr<T, D> u2; // D为deleter
unique_ptr<T, D> u(d); // d为deleter
u = nullptr; // 释放u指向的对象,将u置为空
u.release(); // u放弃对指针的控制权,返回指针,并将u置为空
u.reset(); // 释放u指向的对象
unique_ptr<string> p1(new string("abc"));
unique_ptr<string> p2(p1.release());
unique_ptr<string> p3(new string("Trex"));
p2.reset(p3.release()); // 释放p2原来指向的内存,将p3原先指向的对象的指针绑定到p2
不能拷贝unique_ptr的规则有一个例外:可以拷贝或赋值一个将要被销毁的unique_ptr。最常见的例子是从函数返回一个unique_ptr:
unique_ptr<int> clone(int i) {
return unique_ptr<int>(new int(i));
}
还可以返回一个局部对象的拷贝:
unique_ptr<int> clone(int i) {
unique_ptr<int> ret(new int(i));
return ret;
}
重载unique_ptr中的删除器
重载一个unique_ptr中的删除器会影响到unique_ptr的类型以及如何构造(或者reset)该类型的对象。必须在尖括号中unique_ptr纸箱类型之后提供删除器类型。
unique_ptr<objT, delT> p(new objT, fcn);
// unique_ptr使用类型为delT的对象释放objT对象
// 它会调用fcn的delT类型对象
重写connection的deleter:
void fun(destination &d, ...) {
connection c = connect(&d);
unique_ptr<connection *, decltype(end_connection)*> p(&c, end_conncetion);
}
weak_ptr<T> w;
weak_ptr<T> w(sp); // 与shared_ptr sp指向相同对象的weak_ptr w
w = p; // p可以是一个shared_ptr或一个weak_ptr
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
由于weak_ptr指向的对象因为shared_ptr引用计数降为0而释放,所以在使用之前要检查对象是否还存在,需要调用lock:
auto p = make_shared<int>(42);
weak_ptr<int> wp(p);
if (shared_ptr<int> np = wp.lock()) { // 如果np不为空则条件成立
// 在if语句中,np与p共享对象
智能指针和动态数组
标准库提供了可以管理new分配的数组的unique_ptr版本:
需要在对象类型后面跟一对方括号,支持索引运算符。
unique_ptr<int[]> p(new int[3]{ 1,2,3 });
p[0] = 5;
for (int i = 0; i < 5; ++i) {
cout << p[i] << endl;;
}
p.release(); // 自动调用delete[]销毁其指针
shared_ptr不直接支持管理动态数组,需要提供自己定义的删除器。
shared_ptr<int> sp(new int[10](), [](int *p){ delete[] p;}
for (size_t i = 0; i < 10; ++i) {
*(sp.get() + i) = i; // shared_ptr未定义下标运算,并且不支持算数运算,需要用内置指针来运算
}