C++中的智能指针是用来管理外界资源的,如在堆上边new的资源,当程序还没来得及执行delete操作,函数遇到异常了,没有释放资源,导致内存泄露
如下代码:
void fun() { A *ptr = new A(); /*... ...*/ //程序可能在这行代码中抛出异常,导致ptr所指向堆上的资源没有释放
delete ptr; }
智能指针是怎么解决这个问题的
智能指针在实现上也是一个类,即有构造函数、析构函数,在函数结束之前 类会自动调用析构函数,析构函数会释放资源,所以当遇到异常时,资源也会被正确的释放掉。
接下来介绍 auto_ptr、unique_ptr、 share_ptr、weak_ptr四种智能指针
auto_ptr
auto_ptr是弱智能指针 一个资源只能被一个auto_ptr拥有,当智能指针赋值的时候拥有权就会发生转移,如下代码
因为会发生所有权的转移所以auto_ptr不能用在STL标准容器中
void Fun(auto_ptr<A> &ptr) { cout << ptr -> a << endl; cout << "Fun faction
end" << endl; } //auto_ptr void Test() { auto_ptr<A> aptr(new A(5));
auto_ptr<A> bptr; bptr = aptr; //赋值运算符重载函数 auto_ptr<A> cptr(bptr); //拷贝构造函数
Fun(cptr); //会导致aptr失效,将aptr对资源的拥有权转向了ptr智能指针 cout << cptr -> a << endl; }
share_ptr:
share_ptr 资源可以被多个指针共享,share_ptr 使用引用计数对资源管理, 不可以调用release(),
调用reset()函数当前的share_ptr会释放资源的所有权,引用计数减一,当引用计数为0时,没有指针指向该资源,资源会被释放,
因为资源可以被多个指针指向,所以指针可以赋值、在函数之间传递,存放在STL容器里, use_count()
返回当前指针指向资源的引用计数(use_count()的效率不高)。
share_ptr使用不当会出现循环引用,资源得不到释放,暂时先不看这个问题。
下边时使用share_ptr的相关代码
示范一:
class A{}; shared_ptr<A> aptr(new A()); shared_ptr<A> bptr = aptr; cout <<
aptr.use_count() << endl;
输出
A() 2 ~A()
示范二:
A *a = new A(); shared_ptr<A> aptr(a); shared_ptr<A> bptr = aptr;
//这样写会报错,导致堆上的同一资源被delete了两次 /*A *a = new A(); shared_ptr<A> aptr(a);
shared_ptr<A> bptr(a);*/
unique_ptr
c++11弃用了auto_ptr,unique_ptr替代了auto_ptr,在同一时刻只有一个unique_ptr指向给定的对象,该智能指针是禁止使用拷贝构造函数的
禁止使用赋值运算符重载函数
* 只能使用move()函数对对象的所有权进行转移,
* reset()函数用来重新指定资源
* release 释放所有权 void Fun(unique_ptr<A>& ptr) //必须写成引用 { cout<< ptr -> a <<
endl; } //unique_ptr void Test1() { unique_ptr<A> aptr(new A(10));
unique_ptr<A> bptr; // bptr = aptr; //error // unique_ptr<A> cptr(aptr);
//error bptr = move(aptr); cout<< bptr -> a << endl; aptr.reset(new A(20));
cout<< aptr -> a << endl; Fun(aptr); aptr.release(); // cout<< aptr -> a <<
endl; //error cout<< "Test1() end" <<endl; }
weak_ptr
weak_ptr 弱智能指针,能看到资源的引用计数,但是不会去用这个引用计数,使用weak_ptr指向资源不会使引用计数增加。
为了配合shared_ptr而引入了weak_ptr,weak_ptr是从share_ptr 或
从另一个weak_ptr对象那里构造,不能直接指向一个新new出来的资源,weaker_ptr可以观察资源的引用情况,他没有重载* 和 -> 运算符。
use_count()函数返回资源的引用计数。 在weak_ptr智能指针类中可以有一个成员函数 lcok();
该函数的作用是从被观测的对象返回一个可用的shared_ptr对象,可以将这个对象赋值给一个新的shred_ptr智能指针.
示范代码如下:
//weak_ptr void Test2() { shared_ptr<A> aptr(new A(10)); shared_ptr<A>
bptr(aptr); weak_ptr<A> wptr(aptr); cout << wptr.use_count() << endl;
shared_ptr<A> cptr = wptr.lock(); //获得shared_ptr对象 cout << cptr -> a << endl;
cout << wptr.use_count() << endl; //获得引用计数 aptr.reset(new A(20)); //重新指向一个新的资源
cout << aptr -> a << endl; aptr.reset(); //指向一个空的资源 bptr.reset(); cptr.reset();
cout << wptr.use_count() << endl; shared_ptr<A> dptr = wptr.lock();
//当堆上的对象引用计数为0,被释放的时候,weak_ptr调用lock()返回一个指针空值(nullptr) cout <<
dptr.use_count() << endl; }
在所有的智能指针中析构函数调用的是delete,不是delete[]; 所以在创建智能指针的时候不可以写成 new A[10];
不能new一个数组,导致资源释放的时候发生错误
整体的代码稍后传到Github上
下一篇总结强智能指针shared_ptr引起的循环引用,weak_ptr配合shared_ptr的案例之一.
之后会把Effective C++上对智能指针的条例总结到后续博客中