- 头文件memory
shared_ptr类
- 允许多个指针指向同一个对象;
创建和初始化
shared_ptr<string> p1;
shared_ptr<int> p2 = make_shared<int>(42);
shared_ptr<string> p3 = make_shared<string>(10,'9');
shared_ptr<int> p4 = make_shared<int>();//值初始化
auto p5 = make_shared<vector<string>>();
拷贝和赋值
- 拷贝:递增计数器
auto p = make_shared<int>(42);
auto q(p);
- 赋值:递减等号左边的计数器,递增等号右边的计数器
auto r = make_shared<int>(42);
r = q;//递减r指向对象的引用计数,递增q指向对象的引用计数
- 当指向一个对象的最后一个shared_ptr被销毁时,shared_ptr会自动销毁指向的对象,并释放相关联的内存。
其他操作
-
*p
-
p.get()
:返回内置指针; -
swap(p,q)
:交换指针; -
p.use_count()
:返回与p共享对象的智能指针数量; -
p.unique()
:如果use_count返回1,则返回true,否则返回false; -
p.reset()
:若p是唯一指向其对象的shared_ptr,则释放此对象;如果不是,就把p置空; -
p.reset(q)
:若p是唯一指向其对象的shared_ptr,则释放此对象;令p指向q;shared_ptr<int> p(new int(1024));//正确,使用普通指针初始化智能指针 p = new int(2048); //错误,普通指针不能转化为智能指针 p.reset(new int(2048));//正确,p指向一个新对象,并释放原有对象(因为p是唯一指向原对象的智能指针)
shared_ptr<int> p1(new int(1024)); shared_ptr<int> p2(p1); p1.reset(new int(2048));//此时p1指向2048,而p2指向1024
-
reset()
经常与unique()
一起使用,来控制多个shared_ptr共享的对象:if(!p.unique()) p.reset(new string(*p)); //如果p不是独有该对象,则先制作一份拷贝,使得p指向拷贝的对象 *p+=newVal; //在拷贝对象上进行操作,不会影响其他共享的智能指针
unique_ptr类
- 某个时刻只能有一个unique_ptr指向一个给定对象;
不支持拷贝和赋值!
unique_ptr<int> p1=new int(1024); //错误!!不能转换
unique_ptr<int> p1(new int(1024)); //正确!!
unique_ptr<int> p2(p1); //错误!!不能拷贝
unique_ptr<int> p2=p1; //错误!!不能赋值
- 函数的实参传递和返回值也是拷贝,但是由于返回值拷贝之后,原unique_ptr会被销毁,因此返回一个unique_ptr是正确的,但是实参传递不支持拷贝。
操作:
up.get()
:返回内置指针;up.release()
:up置空,返回普通指针,但是不释放up指向的对象;up.reset()
:释放up指向的对象;up置空;up.reset(q)
:释放up指向的对象(因为up是唯一的指针);令up指向q(新对象);- 通过调用
release()
和reset()
实现“拷贝和赋值”:
unique_ptr<int> p1(new int(1024));// p1->1024
unique_ptr<int> p2(p1.release()); //将对象的所有权从p1转到p2; p2->1024,p1->NULL
unique_ptr<int> p3(new int(2048)); // p3->2048
p2.reset(p3.release());//释放p2指向的对象,然后p2指向p3 p2->2048, p3->NULL
p2.reset(new int(4096)); // p2->4096
weak_ptr类
- 指向一个由shared_ptr管理的对象,一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放,即使有weak_ptr指向该对象。
初始化
- 只能用shared_ptr来初始化weak_ptr:
auto p=make_shared<int>(42);
weak_ptr<int> wp(p); //p指向的对象的计数不会增加
拷贝和赋值
shared_ptr<int> p=make_shared<int>(42);
weak_ptr<int> wp=p; //可以将shared_ptr转化为weak_ptr;
操作:
-
wp.reset()
:wp置空; -
wp.use_count()
:返回与wp共享的shared_ptr的数量; -
wp.expired()
:如果use_count()为0,返回true,否则返回false; -
wp.lock()
:如果expired()为true,返回空shared_ptr指针,否则返回一个指向wp对象的shared_ptr; -
由于weak_ptr指向的对象可能不存在,因此不能使用weak_ptr直接访问对象:
if(shared_ptr<int> np=wp.lock()){*np++}
weak_ptr的作用
-
weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少。weak_ptr是用来解决shared_ptr相互引用时的死锁问题,如果说两个shared_ptr相互引用,那么这两个指针的引用计数永远不可能下降为0,资源永远不会释放。
class B; class A{ public: shared_ptr<B> pb_; ~A(){cout<<"A delete\n";} }; class B{ public: shared_ptr<A> pa_; ~B(){cout<<"B delete\n";} }; void fun(){ shared_ptr<B> pb(new B()); shared_ptr<A> pa(new A()); pb->pa_ = pa; pa->pb_ = pb; cout<<pb.use_count()<<endl; cout<<pa.use_count()<<endl; } int main(){ fun(); return 0; }
- 这种情况下,指向对象A和对象 B指针计数都是2,当退出函数fun()之后,引用计数分别减1,这样对象A和对象B的引用计数都变成1,无法释放内存;
- 如果将其中一个shared_ptr改为weak_ptr,由于weak_ptr不改变对象的引用计数,所以fun()执行时的引用计数分别为2和1,退出fun()之后,分别递减成1和0,导致B对象被释放,释放B的同时也会让A的计数减1,这样AB可以全部被释放;