智能指针的原理及其模拟实现

论坛 期权论坛 脚本     
匿名技术用户   2020-12-28 08:13   982   0

为什么有智能指针:

因为C++中没有回收内存的机制,当我们new一块内存时,如果忘记了delete,会产生异常导致程序奔溃,为了解决这个问题,引入了智能指针来管理内存。

智能指针的原理:

智能指针的原理就是RAII。RAII:资源的分配即初始化,定义一个类来封装资源的分配和释放,在构造函数来进行资源的分配和初始化,在析构函数来释放资源,资源的正常使用。

智能指针其实是一个栈对象,并不是一个指针类型。

C++标准库中的智能指针:

1. auto_ptr:主要是管理权转移,当一个对象构造另一个对象时,转移关系权限。

模拟实现:

template<typename T>
class AutoPtr
{
public:
 AutoPtr(T* ptr)
  :_ptr(ptr)
 {}
 AutoPtr(AutoPtr<T>& ap)
 {
  //权限转移
  _ptr=ap._ptr ;
  ap._ptr =NULL;
 }
 ~AutoPtr()
 {
  if(_ptr!=NULL)
  {
   delete _ptr;
  }
 }
 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;//返回地址
 }
 void display()
 {
  cout<<*_ptr<<endl;
 }
private:
 T* _ptr;
};

Boost库中的智能指针:

2.scoped_ptr:和auto_ptr一样,但不允许拷贝构造和赋值。

模拟实现scoped_ptr

template<typename T>
class ScopedPtr                   //不允许拷贝构造和赋值
{
public:
 ScopedPtr(T* ptr)
  :_ptr(ptr)
 {}
 ~ScopedPtr()
 {
  if(_ptr!=NULL)
  {
   delete _ptr;
  }
 }
 T& operator*()
 {
  return *_ptr;
 }
 T* operator->()
 {
  return _ptr;//返回地址
 }
 void display()
 {
  cout<<*_ptr<<endl;
 }
protected:     //防止拷贝构造和赋值
 ScopedPtr(const ScopedPtr<T>& sp);
 ScopedPtr<T>& operator=(const ScopedPtr<T>& sp);
private:
 T* _ptr;
};


3.shared_ptr:共享内存,采用引用计数的方法。当计数器为0时,释放内存。

模拟实现shared_ptr:

template<typename T>
class SharedPtr
{
public:
 SharedPtr(T* ptr)
  :_ptr(ptr)
  ,_pcount(new int(1))
 {}
 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[](size_t index)
 {
  if((*_pcount)>1)
  {
   --(*_pcount);
   T* Newptr=new T;
   T* Newpcount=new int(1);
   _ptr=Newptr;
   _pcount=Newpcount;
  }
  return _ptr[index];
 }
 T& operator*()
 {
  if((*_pcount)>1)
  {
   --(*_pcount);
   T* Newptr=new T;
   T* Newpcount=new int(1);
   _ptr=Newptr;
   _pcount=Newpcount;
  }
  return *_ptr;
 }
 ~SharedPtr()
 {
  if(--*_pcount==0)
  {
   delete _ptr;
   delete _pcount;
  }
 }
 void display()
 {
  cout<<*_ptr<<" "<<*_pcount<<endl;
 }
private:
 T* _ptr;
 T* _pcount;
};

存在的问题:

(1).线程安全:???

(2).循环引用:为了解决这个问题引入了weak_ptr。

struct Node
{
 int data;
 boost::shared_ptr<Node> _next;
 boost::shared_ptr<Node> _prev;
 //boost::weak_ptr<Node> _next;    //为了解决这种情况,引用了弱指针 
 //boost::weak_ptr<Node> _prev;
 ~Node()
 {
  cout<<"~Node()"<<endl;
 }
};

void test()
{
 boost::shared_ptr<Node> sp1(new Node());
 boost::shared_ptr<Node> sp2(new Node());
 cout<<sp1.use_count() <<endl;
 cout<<sp2.use_count() <<endl;

 sp1->_next =sp2;
 sp2->_prev =sp1;
 cout<<sp1.use_count() <<endl;
 cout<<sp2.use_count() <<endl;
}
此时的运行结果为:1 1 2 2

为什么没有打印析构这句话:因为出现了循环指向对方,各自的引用计数都是2,对方都在等对方先delete,然后自己才能delete,用shared_ptr导致两个都不会delete。

为了解决这个问题,现在我们引入了weak_ptr,weak_ptr是为了shared_ptr准备的,它不能单独使用,他是来辅助shared_ptr的,weak_ptr的构造函数只能接受shared_ptr类型的对象。

(3).定制删除器:shared_ptr只能解决new出来的,对于文件类型,malloc出来的,它就不行,需要我们进行定制解决方法。

class Fclose
{
public:
 void operator()(void *ptr)
 {
  cout<<"fclose"<<endl;
  fclose((FILE*)ptr);
 }
};
class Free
{
public:
 void operator()(void *ptr)
 {
  cout<<"free"<<endl;
  free(ptr);
 }
};
void test4()
{
 boost::shared_ptr<FILE> sp1(fopen("test.txt","w"),Fclose());
 boost::shared_ptr<int> sp2((int*)malloc(sizeof(int)),Free());

}

4.还有scoped_array,shared_array,intrusive_ptr等智能指针。


分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP