一个智能指针的实现
用C++写程序的人都知道内存泄漏这个问题(除非他从来不动态分内存),对STL有了解的人都知道有auto_ptr这么个智能指针,可因为它只能有一个拥有权,所以不能支持标准容器,一直不太喜欢这点。能开发出一个共享访问的智能指针就好多了(这有点像Windows内核对象)。所以,需要有个对象来管理计数问题,这个对象只能和要管理的指针共存亡,当有新的对象指向这块内存时只要把指针给它,计数加1,当一个对象析构时,只要把计数减1,是否释放是这个管理类的事儿。当计数为0时就可以自己了断了。下面我就阐述下我是怎么设计这个类的。
Template class shared_data
shared_data是管理指针并计数的类,我们看看它都需要写哪些函数
template<class T>
class shared_data
{
private:
friend class shared_ptr<T>;
explicit shared_data(T* pT):_M_ptr(pT);
~shared_data() ;
void operator++ ();
operator-- ();
T& operator* () const ;
T* operator-> () const;
bool operator== (T* pT) const ;
T* get() ;
int use_count() ;
private:
T* _M_ptr;
unsigned int _M_nCount;
};
shared_ptr是我们真正要用的,所以,shared_data里的一切我们做成private就可以了,只要让shared_ptr成为自己的友员。
l 操作很简单,我们先看数据区:
1. T* _M_ptr;
这是我们分配出来的对象T的指针,也是我们管理的对象。
2. unsigned int _M_nCount;
这是我们的计数变量,初始时是1,当为0时就把自己给delete。
l 我们再看操作
1. 构造函数用来把管理的指针存入_M_ptr,析构用来释放_M_ptr。
2. operator++()和operator—()用来增加和减少计数,在operator—()中做计数是否为0,决定在什么时候释放资源。
3. operator==()用来判断操作符右边的T指针是否与管理的T指针是同一地址。
4. operator*和operator->就不用说了吧。
5. get()用来返回T*。
6. use_count()用来获取当前有多少个引用。
Template class shared_ptr
shared_ptr是用来定义和操作shared_data的类,所有同类型的shared_ptr可以有多可实例,但只有一个所共享的管理类shared_data,当两个shared_ptr类或shared_ptr和对像T的指针T*操作时,只需要对shared_data进行++和—即可。
template<class T>
class shared_ptr
{
typedef shared_data<T> element;
public:
explicit shared_ptr(T* pT):_M_pD(NULL);
explicit shared_ptr():_M_pD(NULL){};
~shared_ptr() ;
// copy constructor
shared_ptr(const shared_ptr<T>& rT) ;
// assignment operator
shared_ptr<T>& operator = (shared_ptr<T>& rT) ;
shared_ptr<T>& operator = (T* pT);
T& operator* () const ;
T* operator-> () const;
bool operator== (shared_ptr<T>& rT) const;
bool operator== (T* pT) const;
void reset();
private:
element* get_element()const ;
element* _M_pD;
};
l 我们先看数据区
只有一个成员_M_pD,是shared_data对象的指针,有一shared_ptr只能拥有一个shared_data对象,shared_ptr只负责shared_data的分配,不负责释放,其它操作就是对shared_data计数的++和—操作。
l 公用成员函数
1. 有两个构造,一个有参数T*,用来直接分配管理类的。一个没有参数,这时的_M_pD为NULL。析构只做shared_data的—操作。
2. 拷贝构造函数用来从另一个shared_ptr中获取_M_pD并做计数++操作
3. 两个赋值函数一个是对应shared_ptr对象的,而另一个则是对应T*的,不用细说了吧。
4. operator*() 和operator->()只是用来调用shared_data的同名函数,因为shared_data所有操作对用户是不可见的。
5. operator==() 比shared_data多了一个,这个是用来比较_M_pD的地址是否相同,那个只是调用shared_data的同名函数(同上)。
6. reset() 用来置空当前_M_pD,当然也要对它做—操作了。
7. 再说最后一个get_element(),一个内部函数,用来返回_M_pD,在赋值时用到。
User Operator
为了说明我们怎么操作这个类,我们先定义一个测试类
class CTest
{
public:
CTest(int nId){
cout<<"CTest()"<<endl;
m_nId = nId;
}
~CTest(){
cout<<"~CTest()"<<endl;
}
void ShowId()
{
cout<<m_nId<<endl;
}
private:
int m_nId;
};
下面看下我的测试怎么写的
void main()
{
// Test constructor
shared_ptr<CTest> t1(new CTest(1));
// Test copy constructor
shared_ptr<CTest> t2(t1);
// Test assignment operator
shared_ptr<CTest> t3;
t3 = t2;
// Test operator->
t3->ShowId();
// Test operator*
(*t3).ShowId();
// Test operator==
shared_ptr<CTest> t4(new CTest(1));
shared_ptr<CTest> t5(new CTest(2));
t4 = t5;
if (t4 == t5)
cout<<"t4 == t5"<<endl;
else
cout<<"t4 != t5"<<endl;
// Test operator==
CTest *p = new CTest(123);
shared_ptr<CTest> t6(p);
if (t6 == p)
cout<<"t6 == p"<<endl;
else
cout<<"t6 != p"<<endl;
// Test operator==
shared_ptr<CTest> p7;
if (p7 == NULL)
cout<<"p7 == NULL"<<endl;
// Test reset
shared_ptr<CTest> t8(new CTest(2));
t8.reset(new CTest(123));
t8->ShowId();
// Test release
shared_ptr<CTest> t9(new CTest(9));
t9.release();
cout<<t9.get()<<endl;
// Test array
shared_ptr<CTest> t10(new CTest(123));
shared_ptr<CTest> t11[100];
for (int i=0;i<100;i++) {
t11[i] = t10;
}
}
由于水平有限,可能有的地方存在问题,欢迎大家加于改善,在此给出全部代码,供大家参考