正文

我写的智能指针auto_ptr2007-03-20 17:37:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/rickone/24137.html

分享到:

为什么要用这个auto_ptr,一般的C语言指针不够用吗?如果C++里没有new,那一般的指针就够用了,现在的代码都像这样:

int *p=new int[100];

//使用p

delete[] p;

使用p的时候,如果突然出了问题,比如丢出异常,就会中止程序,而不能运行delete,造成内存泄漏,所以在使用的时候,经常要做很多判断,比如

if(p)
{
   ...
   delete[] p;
}

if(XXX)
{
   delete[] p;
   throw(xx);
}

所以,拿到内存容易,但责任就大啊,所以整个代码被整个乱七八糟,而且程序员还要保持清醒的头脑,一不小心就。。。

STL的auto_ptr就是为了解决这个问题,做的一个封装,在指针的运算过程中,比如*,->,发生错误,丢异常,并在析构的时候delete。

把VC6里的auto_ptr复制下:

template<class _Ty>
 class auto_ptr {
public:
 typedef _Ty element_type;
 explicit auto_ptr(_Ty *_P = 0) _THROW0()
  : _Owns(_P != 0), _Ptr(_P) {}
 auto_ptr(const auto_ptr<_Ty>& _Y) _THROW0()
  : _Owns(_Y._Owns), _Ptr(_Y.release()) {}
 auto_ptr<_Ty>& operator=(const auto_ptr<_Ty>& _Y) _THROW0()
  {if (this != &_Y)
   {if (_Ptr != _Y.get())
    {if (_Owns)
     delete _Ptr;
    _Owns = _Y._Owns; }
   else if (_Y._Owns)
    _Owns = true;
   _Ptr = _Y.release(); }
  return (*this); }
 ~auto_ptr()
  {if (_Owns)
   delete _Ptr; }
 _Ty& operator*() const _THROW0()
  {return (*get()); }
 _Ty *operator->() const _THROW0()
  {return (get()); }
 _Ty *get() const _THROW0()
  {return (_Ptr); }
 _Ty *release() const _THROW0()
  {((auto_ptr<_Ty> *)this)->_Owns = false;
  return (_Ptr); }
private:
 bool _Owns;
 _Ty *_Ptr;
 };

代码在<memory>里,写得比较丑陋,忍住胃看吧。但是它还是有问题,在《C++Primer》里写了一些注意,所以程序员还是要甚用。(听说BOOST里有完全安全的auto_ptr,不知道怎么写的)

我的程序完全是照着那些缺陷做的,是用一个map表保存堆内在的分配情况,比如一个堆上的对象指针被分发给几个auto_ptr,那只有在最后一个析构的时候去delete,怎么实现?用使用计数器,就像文件一样,把堆上的内存看成资源,资源可以被多个‘人’打开,打开一次,计数器+1,关闭一次-1,最后一个关闭的时候进行析构,另外对于数组的情况,只用做一个标记就行了。

(异常部分没写,只做个框架)

#include <map>
#ifndef HEAPPTR_2007
#define HEAPPTR_2007

template<class T>
class heap_ptr
{
 //enum{tag=t};
 T* ptr;
 bool bArray;
 static std::map<T*,int> use_count;
public:
 heap_ptr():ptr(0){};
 heap_ptr(T* q, bool b=false){
  bArray=b;
  attach(q);
 };
 ~heap_ptr(){
  detach();
 };
 // *,->和[]运算符
 T& operator*(){
  return *ptr;
 };
 T* operator->(){
  return ptr;
 };
 T& operator[](int index){
  return ptr[index];
 };
 // 拷贝构造函数和赋值函数
 heap_ptr(heap_ptr &hp){
  attach(hp.ptr);
  bArray=hp.bArray;
 };
 heap_ptr& operator=(heap_ptr &hp){
  detach();
  attach(hp.ptr);
  bArray=hp.bArray;
 };
 //
 void attach(T* q){
  std::map<T*,int>::iterator it=use_count.find(q);
  if(it==use_count.end())
  {
   use_count[q]=1;
  }
  else
  {
   use_count[q]++;
  }
  ptr=q;
 };
 void detach(){
  if(ptr)
  {
   int c=--use_count[ptr];
   if(c==0)
   {
    use_count.erase(ptr);
    if(bArray)
     delete[] ptr;
    else
     delete ptr;
   }
  }
 };
 
};

#define USE_HEAPPTR_ON(TYPE) \
 std::map<TYPE*,int> heap_ptr<TYPE>::use_count;

#endif

由于只用于堆上的动态内存,所以干脆叫heap_ptr,最后的宏是为了初始化静态成员,如果要使用某个类在堆上的内存,在使用的地方,在全局定义的位置,加上这句宏就可以了。

使用:

#include "stdafx.h"
#include "heapptr.h"
#include <iostream>
using namespace std;

USE_HEAPPTR_ON(int)

void foo1(heap_ptr<int> p)
{
 *p=1;
}
void foo2(heap_ptr<int> p)
{
 *p=2;
}
void foo3(heap_ptr<int> p)
{
 p[0]=3;
}
void foo4(heap_ptr<int> p)
{
 p[1]=4;
}
int main(int argc, char* argv[])
{
 printf("Hello World!\n");
 heap_ptr<int> p(new int(0));
 heap_ptr<int> q(new int[10],true);
 foo1(p);
 cout<<*p<<endl;
 foo2(p);
 cout<<*p<<endl;
 foo3(q);
 foo4(q);
 cout
  <<q[0]<<endl
  <<q[1]<<endl;
 return 0;
}

阅读(7096) | 评论(3)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册