在动态内存管理过程,要注意释放动态内存的正确时间,若是不释放的话,会形成内存泄露;可是释放时若还有指针引用内存的话,会产生引用非法内存的指针。而智能指针就是为了解决这一难点而诞生的,就如它的名字同样,若是你使用智能指针的话,它就会智能的在合适的时机释放掉内存。智能指针包括shared_ptr,unique_ptr和weak_ptr.安全
shared_ptr和unique_ptr支持的操做;函数
shared_ptr<T>sp; //T为参数类型,默认为空指针 unique_ptr<T>up; *p;//解引用 p->get();//返回智能指针保存的指针 swap(p,q);//交换p和q种的指针 //构造一个shared_ptr make_shared<T>(arg);//返回一个shared_ptr对象,并用arg来初始化它 shared_ptr<T>p(q);//用q来初始化p p.use_count();//返回p种的计数。
咱们能够认为每一个智能指针都有绑定一个计数器,一般称其为引用计数。不管咱们什么时候拷贝一个智能指针,计数器都会递增,例如指针
①用一个shared_ptr初始化另外一个shared_ptrcode
shared_ptr<T>p(q);//q中的计数器会加一
②将智能指针做为参数传递对象
int func(std::shared_ptr<int>p){ return p->use_count(); } int mian(){ std::shared_ptr<int>p = std::make_shared<int>(10); std::cout<<func(p);//输出的结果为2 }
③做为参数的返回值:内存
shared_ptr<T> func();
shared_ptr的构造函数时explict修饰的,所以咱们不能将一个指针隐式转换为智能指针。作用域
shared_ptr<int>p = new int(10);//错误,不能将内置指针转换为智能指针 shared_ptr<int>p(new int(10));//ok
另外shared_ptr还支持reset操做来改变智能指针绑定的指针。get
p.reset();//p取消与指针的绑定,变成默认的nullptr; p.reset(new int(20));//p与新的匿名地址绑定。
unique_ptr与shared_ptr不一样的是,它不可以拷贝,也就是说它的计数器是能小于等于1.当unique_ptr被销毁的时候,它指向的对象也将被销毁。内存管理
unique不支持拷贝和赋值:io
std::unique_ptr<int>p(new int(10));//ok,直接初始化。 std::unique_ptr<int>q(p);//错误,不能拷贝 q = p;//错误,不能赋值
unique支持reset和release操做:
reset的操做和shared_ptr的reset操做相同,release操做会返回当前智能指针保存的对象并将智能指针置为空。经过这两个操做能够进行unique_ptr指向对象的专业。
p.reset(q.release());//将q保存的对象转移给p。
shared_ptr和unique_ptr默认为用delete删除对象,也能够自定义删除器
shared_ptr的自动删除器定义以下:
假设如今有class 为connection,删除函数为disconnect(connection *con);那么自动删除定义删除器为:
std::shared_ptr<connection>p(new connection(),disconnect); //第二个参数为自定义的删除器函数。
unique_ptr的自动删除器要在参数列表指明删除器的函数指针类型,这里用decltype函数自动推导。
std::unique_ptr<connection,decltype(disconnect)*>p (new connection(10),disconnect);
weak_ptr是一种不控制对象生长周期的智能指针,它指向一个shared_ptr指向的对象,将weak_ptr绑定到一个shared_ptr保存的对象上,也不会增长shared_ptr的计数器。一旦最后一个指向对象的shared_ptr被销毁,对象将被释放,即便还有weak_ptr绑定这个对象。
std::shared_ptr<int>p(new int(10)); std::weak_ptr<int>wp(p);//wp若共享p,p的引用计数不会改变
因为对象不存在,因此不能用wp直接访问对象,而是用成员函数lock来检查指向的对象是否存在,lock就返回一个指向的shared_ptr.与其它shared_ptr不一样,只要此shared_ptr存在,它的底层对象就一直存在。
if(shared_ptr<int>np = wp.lock())//只有np不为空时才能进入if { //在if中使用共享对象np是安全的,np和p共享对象。 }
class B; class A{ public: A(){ std::cout<<"A construction"<<std::endl; } ~A(){ std::cout<<"A destruction"<<std::endl; } std::shared_ptr<B>pb; }; class B{ public: B(){ std::cout<<"B construction"<<std::endl; } ~B(){ std::cout<<"B destruction"<<std::endl; } std::shared_ptr<A>pa; }; int main(){ std::shared_ptr<A>a(new A()); std::shared_ptr<B>b(new B()); a->pb = b; b->pa = a; }
上面的代码的输出是什么呢?
A construction B construction
没错,能够很显然的看到A和B在主函数结束后并无被销毁,由于A和B互相持有对方的引用计数,二者的引用计数都不会较小到0,所以内存也不会被释放。
而将代码修改到以下后:
class B; class A{ public: A(){ std::cout<<"A construction"<<std::endl; } ~A(){ std::cout<<"A destruction"<<std::endl; } std::weak_ptr<B>pb; }; class B{ public: B(){ std::cout<<"B construction"<<std::endl; } ~B(){ std::cout<<"B destruction"<<std::endl; } std::weak_ptr<A>pa; }; int main(){ std::shared_ptr<A>a(new A()); std::shared_ptr<B>b(new B()); a->pb = b; b->pa = a; }
输入为
A construction B construction B destruction A destruction
前面咱们说过weak_ptr时弱共享,不会增长shared_ptr的计数引用,所以A和B只有自己一个计数引用,当自身离开做用域后,计数器归0,释放内存。