1.shared_ptr<>:允许多个指针指向同一个对象
初始化方式:
shared_ptr<int> p1 = make_shared<int>(10);//最好使用这种方式
shared_ptr<int> p2(new int(20)); //只能用直接初始化方式
和普通指针有一样的操作,*,->,swap等
支持拷贝与赋值与自定义删除器,特别地:
p.get()能返回p中保存的指针,如果指针指针释放了其对象,返回指针所指的对象也就消失了。
p.use_count()返回与p共享的只能指针数量,比较慢,主要用来调试。
p.unique()若p.use_count()为1,返回true,否则返回false。
shared_ptr会自动销毁所管理的对象并且会自动释放相关联的内存。
原因是因为内存采用了:引用计数。
当计数为0就会自动释放。
p1 = p2; //p2引用计数加1,p1引用计数减1
不能将一个内置指针隐式转化为指针指针
shared_ptr<int> f(int p)
{
return shared_ptr<int>(new int(p));//不能直接放回new int(p)
}
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); //q为内置指针,d为可调用对象作为删除器
shared_ptr<T> p(p2, d);//p是shared_ptr2的拷贝,p使用对象d作为删除器
p.reset(); //释放p,将p置为空
p.reset(q); //p会指向q
p.reset(q, d); //调用删除器d
shared_ptr不支持管理动态数组,当初始化动态数组时必须定义自己的删除器:
shared_ptr<int> p(new int[10], [](int *n){ delete[]n; });//必须要自定义删除器
因此访问数组中的元素操作也会不同:
for(int i = 0; i < 10; ++i)
{
*(p.get() + i) = u(e);//只能通过get()来访问
}
注意:不要用get初始化另一个智能指针或者为另一个智能指针赋值
2.unique_ptr<>:独占所指向的对象,也就是同一时刻只能有一个unique_ptr指向一个给定的对象
初始化形式:
unique_ptr<int> p(new int(10)); //只能直接初始化
不支持拷贝与赋值
支持自定义删除器,和普通指针也有*,->,swap等,也有get()函数
unique_ptr<T> u1; //指向类型为T的对象,会使用delete
unique_ptr<T, D> u2; //会使用删除器D来释放
unique_ptr<T, D> u(d);//空unique_ptr,使用d来代替delete
u = nullptr; //释放u所指的对象,将u置为空
u.release(); //u放弃对指针的控制权,返回指针,将u置为空
u.reset(); //释放u所指的对象
u.reset(q); //如果提供内置指针q,令u指向这个对象
u.reset(nullptr);
unique_ptr能够管理动态数组:
unique_ptr<int[]> a;
unique_ptr<int[]> a(new int[10]); //注意类型
能够使用u[i]访问数组
其他操作和普通一样
3.weak_ptr<>:不控制所指向对象生存期的只能指针,指向由一个shared_ptr管理的对象
初始化形式:
weak_ptr<int> w; //p必须为shared_ptr
weak_ptr<int> w = p;
weak_ptr<int> w(p);
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
注意:由于对象可能不存在,不能直接访问对象,需要使用lock
weak_ptr有一个非常有用的地方在于,破除shared_ptr的循环引用:
class A
{
public:
A(int a) : i(a) {}
...
public:
int i;
shared_ptr<int> p;
};
int main()
{
shared_ptr<A> one = make_shared<A>(1);
shared_ptr<A> two = make_shared<A>(2);
one->p = two;
two->p = one;
return 0;
}
这种情况造成了循环引用,作用域结束时one和two都不会被释放,正确的做法是将one和two其中一个变为weak_ptr
class A;
class B;
class A
{
private:
shared_ptr<B> p;
};
class B
{
private:
shared_ptr<A> p;
};
这种情况也造成了循环引用,应该讲其中一个变为weak_ptr