自己实现auto_ptr,与std::auto_ptr一样。
头文件 _auto_ptr.h
#ifndef __auto_ptr_H_
#define __auto_ptr_H_
//#define __debug
// _auto_ptr.h
// 自己实现一个auto_ptr
#include <iostream>
using namespace std;
template <typename T>
class _auto_ptr;
template <typename Y>
class tmp_class
{
public:
explicit tmp_class(Y *tp_):tp(tp_){}
Y *tp;
};
template <typename T>
class _auto_ptr
{
public:
_auto_ptr():p(0)
{
#ifdef __debug
cout<<"_auto_ptr():empty construction of _auto_ptr"<<endl;
#endif
}
template <typename U>
explicit _auto_ptr(U *pu):p( pu ) // 此处若写为 p(pu),则只接受原始指针的兼容赋值(一般是子类指针赋值给基类),
// 若写为p((T*)pu),则进行了强制转换,使得float指针可以赋值给int指针
// explicit抑制隐式转换
{
if(pu)
{
#ifdef __debug
cout<<"_auto_ptr(U *pu): construction of _auto_ptr, obj="<<p<<" "<<endl;
#endif
}else
{
#ifdef __debug
cout<<"_auto_ptr(U *pu): construction of _auto_ptr, null=null"<<endl;
#endif
}
}
_auto_ptr( _auto_ptr<T>& cp):p( 0 )
{
p=cp._release();
#ifdef __debug
cout<<"_auto_ptr(const _auto_ptr<T>& cp):copy construction of _auto_ptr.obj="<<p<<" "<<endl;
#endif
}
//template<class U>
operator tmp_class<T> ()
{
#ifdef __debug
cout<<"_auto_ptr: hidden convert"<<endl;
#endif
return tmp_class<T>(this->_release());
//return tmp_class<T>(this->p); // 用这句话代替上面一行代码,会发生什么?
// 由于auto_ptr的独占性,本对象(A)将指针(控制权)转交给别人(B)以后,A的指针必须
// 赋值为NULL,否则当A析构时,会将内存释放,而B还在继续使用该内存单元.
// 这一点对 new T 产生的临时对象同样适用,因为该临时对象是可写的。(very important)
}
// template<class U> // 如果加上这句,就成为成员函数模板,本函数内的<T>全部换为<U>即可
_auto_ptr( tmp_class<T> cp):p( cp.tp )
{
#ifdef __debug
cout<<"_auto_ptr: tmp_class<T> construction"<<endl;
#endif
} // tmp_class<T> cp不能为引用
_auto_ptr<T>& operator=(_auto_ptr <T>&cp)
{
if(&cp==this)
return *this;
_clear();
p=cp._release();
#ifdef __debug
cout<<"_auto_ptr::operator=:operator"<<"obj="<<p<<" "<<endl;
#endif
return *this;
}
~_auto_ptr()
{
#ifdef __debug
cout<<"~_auto_ptr()"<<endl;
#endif
_clear();
}
T *operator->() {return &(operator*());}
T &operator*() {return *p;}
T* get()
{
return p;
}
private:
void _clear()
{
delete p;
p=0;
}
T *_release()
{
T *tmp=p;
p=0;
return tmp;
}
private:
T *p;
};
#endif
main.cpp
#include <iostream>
#include <memory>
#define __debug
#include "_auto_ptr.h"
using namespace std;
class T
{
public:
T(int v):y(v){cout<<"T 构造"<<endl;}
~T(){cout<<"T 析构"<<endl;}
int y;
friend ostream &operator<<(ostream &os, const T &t);
};
ostream &operator<<(ostream &os, const T &t)
{
cout<<t.y;
return os;
}
int main()
{
_auto_ptr<T>p3= _auto_ptr<T>(new T(4) );
cout<<(*p3).y<<endl;
return 0;
}
结果:
chen@chen-book1:~$ g++ -o cpp c.cpp -g
chen@chen-book1:~$ ./cpp
T 构造
_auto_ptr(U *pu): construction of _auto_ptr, obj=0x9605008
_auto_ptr: hidden convert
_auto_ptr: tmp_class<T> construction
~_auto_ptr()
4
~_auto_ptr()
T 析构
chen@chen-book1:~$
_auto_ptr需要注意的是:
不能共享,一个萝卜一个坑!
所以:
【1】因为不能共享,所以拷贝构造/赋值之后,原有的指针就失去了控制权。
【2】拷贝构造和operator=的参数是引用而不是常引用。这带来一个问题,就是临时对象怎么办?就像代码中
_auto_ptr<T>p3= _auto_ptr<T>(new T(4) );
这使用了另外一个类来中转。它接受临时对象的指针来构造自己,再作为参数对auto_ptr进行构造。这需要一个tmp_class类型参数的构造函数,并将临时对象隐式转换为tmp_class。同时临时对象将自己的指针设置为null,从而交出了控制权。注意new出来的临时对象并非只读,而是可以改变的。