C++总结1—shared_ptr

一、智能指针介绍
(1)C++11:头文件<memory>
     aotu_ptr(已经在C++11中不使用了)
     缺点:智能指针的设计必须要符合实际指针的应用---可以允许多个指针指向同一块空间,将一个指针赋值给另一个指针时这 两个指针都可以指向统一空间;而auto_ptr的设计方式只允许一块空间上只能有一个指针指向它;\
     unique_ptr(就是boost库中的scoped_ptr);\
     weak_ptr:用来解决shared_ptr中的循环引用问题,配合shared_ptr使用;\
     shared_ptr:就是boost库中的shared_ptr\
(2)Boost:scoped_ptr\shared_ptr\weak_ptr

(3)设计智能指针的目的:编写程序中时不时需要new/delete空间,但是可能因为程序逻辑而导致忘记释放资源,造成裸指针,如下列代码示例:

int main

{

   int *p = new int ;

   if(......)

       return ;//由于程序逻辑导致裸指针

   delete p;

   return 0;

}

(4)设计方法思想:通过利用栈上对象在出了作用域后自动调用析构函数释放其所占用的其他资源;
二、shared_ptr
(1)是一个引用计数器的指针,用于共享对象的所有权;
(2)自己设计的shared_Ptr代码示例
//资源管理类
class HeapManager { public: void addRef(void *ptr) { if( ptr != NULL ) { vector<ResItem>::iterator it = _vec.begin(); for(; it != _vec.end();++it) { if( it->paddr == ptr ) { it->refcount++; return ; } } //结构体定义变量 将这个新得资源添加到Item中 ResItem item(ptr); _vec.push_back(item); } } void delRef(void *ptr) { vector<ResItem>::iterator it = find(_vec.begin(),_vec.end(),ptr); if( it != _vec.end() ) { it->refcount--; } } int getRef(void *ptr) { vector<ResItem>::iterator it = find(_vec.begin(),_vec.end(),ptr); if( it != _vec.end() ) { return it->refcount; } } private: struct ResItem { ResItem(void *ptr = NULL):paddr(ptr),refcount(0) { if( ptr != NULL ) { refcount = 1; } } //==运算符的重载函数,由于HeapManager中存放的是RefItem类型,而我们传的是void*指针,因此要提供==运算符重载函数 bool operator == (void *ptr) { return paddr = ptr; } void *paddr; int refcount; }; vector<ResItem> _vec; }; template <typename T> class Shared_Ptr { public: Shared_Ptr( T* ptr = NULL):_ptr(ptr) { //如果有指针引用资源,那么则增加该资源的引用计数器 if( ptr != NULL ) addRef(); } ~Shared_Ptr() { //如果有指针不再指向此资源,则计数器减1 delRef(); //如果指向该块资源的引用计数变为0,则说明当前没有指针指向资源,则释放掉资源; if( 0 == getRef() ) { delete _ptr; } } Shared_Ptr( const Shared_Ptr &src ):_ptr(src._ptr) { //如果有指针引用资源,那么则增加该资源的引用计数器 if( _ptr != NULL ) addRef(); } Shared_Ptr<T>& operator = (const Shared_Ptr<T> src) { //要将src的指针给另一指针,说明自己不再引用资源,要将资源对应的引用计数器减1 delRef(); if( this == &src ) return this; //检查指针原先引用的资源计数器是否为0 若是0,则释放资源; if( 0 == getRef() ) delete _ptr; _ptr = src._ptr; return *this; } //*运算符重载函数 T& operator *() { return *_ptr; } //->运算符重载函数 T* operator ->() { return _ptr; } void addRef() { _HeapManager.addRef(_ptr); } void delRef() { _HeapManager.delRef(_ptr); } int getRef() { return _HeapManager.getRef(_ptr); } private: T* _ptr; static HeapManager _HeapManager;//所有智能指针共享一个堆资源管理; }; //静态函数类外初始化;新建一个HeapManager类的对象 template <typename T> HeapManager Shared_Ptr<T> :: _HeapManager; int main() { int a = 10 ; Shared_Ptr<int> pa(&a); *pa = 20 ; cout<<"pa->a = "<<a<<endl; Shared_Ptr<int> pb = pa; *pb = 200; cout<<"pb->a = "<<a<<endl; /*Shared_Ptr<int> pb (new int); Shared_Ptr<int> pc = pa;*/ return 0;
}
(3)C++中shared_ptr的常用接口

1.构造函数带一个参数
template <typename T>
explicit shared_ptr<T* p>
构造函数获得指针p的所有权,p必须为指向T的有效指针,然后引用计数加1,抛出的异常为“std::bad_alloc”
2.构造函数带两个参数
template <typename T,typename D>
explicit shared_ptr<T* p,D d>
d为shared_ptr被销毁时负责释放资源的一个对象,被保存的资源将以d(p)的形式传给d对象,抛出的异常为“std::bad_alloc”
3.拷贝构造函数
shared_ptr<const shared_ptr& p>
p中保存的资源被新构造的shared_ptr共享,引用计数加1
4.从weak_ptr构造shared_ptr
template <typename T>
explicit shared_ptr<const weak_ptr<t>& p>
这种方式使得weak_ptr具有线程安全,指向weak_ptr参数的共享资源的引用计数将会自增,如果weak_ptr为空(p.use_count()==0),则抛出抛出的异常为“std::bad_alloc”
5.析构函数
 ~shared_ptr();
    shared_ptr析构函数,对引用计数减一。如果计数为零,则保存的指针被删除。删除指针的方法是调用operator delete,或者,如果给定了一个执行删除操作的删除器对象,就把保存的指针作为唯一参数调用这个对象。析构函数不会抛出异常
6.由auto_ptr构造shared_ptr
template <typename T>
    shared_ptr(auto_ptr<T>& r);
    这个构造函数从一个auto_ptr获取r中保存的指针的所有权,方法是保存指针的一份拷贝并对auto_ptr调用release。构造后的引用计数为1,而r则变为空的。如果引用计数器不能分配成功,则抛出std::bad_alloc。
 7.赋值运算符重载
   shared_ptr& operator=(const shared_ptr& r);
    赋值操作共享r中的资源,并停止对原有资源的共享。赋值操作不会抛出异常。
8.代码示例

{
shared_ptr<int> pInt1;
assert(pInt1.use_count() == 0);         // 还没有引用指针
{
  shared_ptr<int> pInt2(new int(5));
  assert(pInt2.use_count() == 1);        // new int(5)这个指针被引用1次
  pInt1 = pInt2;
  assert(pInt2.use_count() == 2);       // new int(5)这个指针被引用2次
  assert(pInt1.use_count() == 2);
}                                                   //pInt2离开作用域, 所以new int(5)被引用次数-1

assert(pInt1.use_count() == 1);
}         // pInt1离开作用域,引用次数-1,现在new int(5)被引用0次,所以销毁它


猜你喜欢

转载自blog.csdn.net/weixin_41966991/article/details/81055269
今日推荐