C++---智能指针

在代码中经常忘记释放动态开辟的内存资源,造成内存泄露,并且在操作时要小心谨慎,避免内存泄露,因此产生了只能指针来动态的管理指针所指向的动态资源释放
auto_ptr:管理权的转移操作,存在缺陷
scoped_ptr:一种粗暴模式的防拷贝
shared_ptr:在需要拷贝的地方增加了引用计数功能
weak_ptr:具有弱指针功能,主要配合解决shared_ptr循环引用

auto_ptr

作用:是一种将权限转移的方式(一个指针将一块空间的管理权限交给另一个指针)

C++---智能指针

template<class T>
class AutoPtr
{
public:
 AutoPtr(T* ptr)
  :_ptr(ptr)
 {}
 ~AutoPtr()
 {
  printf("~ptr\n");
  delete _ptr;
 }
 AutoPtr(AutoPtr<T>& ap)
 {
  _ptr=ap._ptr;
  ap._ptr=NULL;
 }
 AutoPtr<T>& operator=(AutoPtr<T> &ap)
 {
  if(this!=&ap)
  {
   delete _ptr;
   _ptr=ap._ptr;
   ap._ptr=NULL;
  }
  return *this;
 }
 T& operator*()
 {
  return *_ptr;
 }
 T& operator->()
 {
  return _ptr;
 }
private:
 T* _ptr;
};
void TestAutoPtr()
{
 AutoPtr<int> apl(new int(10));
 AutoPtr<int> ap2(ap1);
 //此时ap1已经被置为空了,这时给*ap1赋值就会出现问题
 *ap2=200;
 AutoPtr<int> ap3(new int(10));
 ap3=ap2;//此时ap2被置为NULL
}

auto_ptr优点:实现智能管理指针指向动态资源的释放

缺点:就像拷贝构造函数和赋值运算符函数一样,比如拷贝构造函数,用ap2拷贝ap1,但是当拷贝完成后,发现ap1内部指针被置空了,当我们再次调用ap1时,发现对象已经被释放了,所以程序就会崩溃

C++---智能指针

scoped_ptr

这个指针以一种简单粗暴的模式直接抛弃的auto_ptr的缺点,这个指针直接不允许拷贝和赋值
实现这种机制的方法有两种:
1.将拷贝构造函数和赋值操作符函数声明为私有的
2.只声明构造函数和赋值操作符函数,不定义

template<class T>
class ScopedPtr
{
public:
 ScopedPtr(T* ptr)
  :_ptr(ptr)
 {}
 ~ScopedPtr()
 {
  cout<<"~ScopedPtr()"<<endl;
 }
 T& operator*()
 {
  return *_ptr;
 }
 T& operator->()
 {
  return _ptr;
 }
private:
 T* _ptr;
 ScopedPtr(const ScopedPtr<T>& sp);
 ScopedPtr<T>& operator=(const ScopedPtr<T> &sp);
 //用这种简单粗暴的方式防止你在外面调用这两种函数
};

shared_ptr

像指针一样,但会记录有多少个shared_ptrs共同指向一个对象,引用计数,一旦最后一个这样的指针被销毁,也就是一旦某个对象的引用计数变为0,这个对象会被自动删除。这在非环形数据结构中防止资源泄露很有帮助。这样指针可以共享一块内存,并且不用考虑内存泄露问题

优点:
1.多个指针指向同一个内存空间,释放后,不会造成内存泄露
2.更加安全便捷的管理内存空间
3.可以安全的进行赋值操作符函数和拷贝构造函数
4.多个指针共同管理一块空间,从而更加智能

template<class T>
class SharedPtr
{
public:
 SharedPtr(T* ptr,int *pcount)
  :_ptr(ptr)
  ,_pCount(pcount)
 {
  cout<<"SharedPtr"<<endl;
 }
 ~SharedPtr()
 {
  if(--(*_pCount)==0)
  {
   delete[] _ptr;
   delete[] _pCount;
   cout<<"~SharedPtr"<<endl;
   _ptr=NULL;
   _pCount=NULL;
  }
 }
 SharedPtr(const  SharedPtr<T>& sp)
 {
  _ptr=sp._ptr;
  _pCount=sp._pCount;
  ++(*_pCount);
 }
 SharedPtr<T>& operator=(const SharedPtr<T>& sp)
 {
  if(this != &sp)
  {
   if(--(*_pCount)==0)
   {
    delete _ptr;
    delete _pCount;
   }
   _ptr=sp._ptr;
   _pCount=sp._pCount;
   ++(*_pCount);
  }
  return *this;
 }
 T& operator*()
 {
  return *_ptr;
 }
 T* operator->()
 {
  return _ptr;
 }
protected:
 T* _ptr;
 int* _pCount;
};

但是会产生循环引用的问题

struct ListNode
{
 SharedPtr<ListNode> _next;
 SharedPtr<ListNode> _prev;
 ListNode()
  :_prev(NULL)
  ,_next(NULL)
 {}
 ~ListNode()
 {
  cout<<"delete ListNode"<<endl;
 }
}
void TestSharedPtrCycle()
{
 SharedPtr<ListNode> cur=new ListNode;
 SharedPtr<ListNode> next=new ListNode;
 cur->_next=next;
 next->_prev=cur;
}

C++---智能指针

weak_ptr

弱指针,专门解决shared_ptr循环引用问题,只引用不计数

template<class T> class WeakPtr; template<class T>
class SharedPtr
{
 friend class WeakPtr<T>;
public:
 SharedPtr(T* ptr)
  :_ptr(ptr)
  ,_pCount(new int(1))
 {
  cout<<"SharedPtr"<<endl;
 }
 SharedPtr(const SharedPtr<T>& sp)
 {
  _ptr=sp._ptr;
  _pCount=sp._pCount;
  (*_pCount)++;
 }
 SharedPtr<T>& operator=(const SharedPtr<T>& sp)
 {
  if(this!=&sp)
  {
   if(--(*_pCount)==0)
   {
    delete _ptr;
    delete _pCount;
   }
   _pCount=sp._pCount;
   _ptr=sp._ptr;
   (*_pCount)++;
  }
  return *this;
 }
 ~SharedPtr()
 {
  if(--(*_pCount)==0)
  {
   if(_ptr)
   {
    delete _ptr;
   }
   delete _pCount;
  }
 }
 T& operator*()
 {
  return *_ptr;
 }
 T* operator->()
 {
  return _ptr;
 }
 int Count()
 {
  return *_pCount;
 }
protected:
 T* _ptr;
 int* _pCount;
};
template<class T>
class WeakPtr
{
public:
 WeakPtr(SharedPtr<T>& sp)
  :_ptr(sp.ptr)
 {}
 WeakPtr()
  :_ptr(NULL)
 {}
 T& operator*()
 {
  return *_ptr;
 }
 T* operator->()
 {
  return _ptr;
 }
protected:
 T* _ptr;
};
struct ListNode
{
 WeakPtr<ListNode> _next;
 WeakPtr<ListNode> _prev;
 ~ListNode()
 {
  cout<<"delete ListNode"<<endl;
 }
};
void TestSharedPtrCycle()
{
 SharedPtr<ListNode> cur=new ListNode;
 SharedPtr<ListNode> next=new ListNode;
 //使用弱指针来负责cur->next,next->prev的指向,使其引用计数不在加一
 cur->_next=next;
 next->_prev=cur;
 cout<<cur.Count()<<endl;
 cout<<next.Count()<<endl;
}

弱指针是指当指针指向原来空间时,引用计数不在进行加1,释放时可直接释放,因此解决了循环引用的问题,不是管理指针,而是配合shared_ptr避免了一次引用计数