小议auto_ptr
一直以来都以为auto_ptr是个易用的东西,虽然一直都 没有用过它.直到昨天,终于用了一下VC版本的auto_ptr, 结果许多行为令人费解. 没有办法,又重新把STL参考书研究了一遍,随后把VC版 的auto_ptr源码翻来研究了一番,原来是.....
有所得,总结了如下一些东东,望对初学者有所帮助.同 时,若有不对的地方望各位大虾多指教. 详细解说见代码注解!
//auto_ptr.h
#ifndef AUTO_PTR__H__ #define AUTO_PTR__H__
//声明: //1.以下源代码仅供学习.任何使用过程中所造成的后果与作者无关. //2.如果您使用了,表示您接受该声明
//作者 古斌亮 //时间 2003.06.21 //email: [email protected]
//vc auto_ptr:仿照VC版的auto_ptr行为写的一个auto_ptr namespace vc { template<class T> class auto_ptr { public: explicit auto_ptr(T * p = NULL):_own(p!=0), _ptr(p){} public: auto_ptr(const auto_ptr<T>& y): _own(y._own), //拥有权转移到目标 _ptr(y.release()){} auto_ptr<T>& operator=(const auto_ptr<T>& y) { if(this!=&y) { if(_ptr!=y._ptr)//是否同一个对象 { if(_own)//是否具备拥有权 { delete _ptr; _ptr = NULL; } _own = y._own; } else if(y._own)_own = true; _ptr = y.release();//拥有权转移到目标 } return (*this); } ~auto_ptr() { if(_own)//如果具备拥有权 { delete _ptr; _ptr = NULL; } }
public: T& operator*() const { return (*_ptr); }
T *operator->() const { return (_ptr); }
public: T * release() const { ((auto_ptr<T>*)this)->_own = false;//拥有权转移到目标 return (_ptr); }
private: bool _own;//记录是否拥有权 T * _ptr;//引用指针 }; };//namespace vc
//stl auto_ptr:仿照STL版的auto_ptr行为写的一个auto_ptr namespace stl { template<class T> class auto_ptr { public: explicit auto_ptr(T * p = NULL):_ptr(p){} public: auto_ptr(auto_ptr<T>& y):_ptr(y._ptr)//拥有权转移到目标 { y._ptr = NULL;//释放拥有权 } auto_ptr<T>& operator=(const auto_ptr<T>& y) { if(this!=&y) { if(_ptr)//释放原先拥有的对象 { delete _ptr; _ptr = NULL; }
_ptr = y._ptr;//拥有权转移到目标 y._ptr = NULL;//释放拥有权 } return (*this); } ~auto_ptr() { delete _ptr;//释放拥有的对象 }
public: T& operator*() const { return (*_ptr); }
T *operator->() const { return (_ptr); }
private: T * _ptr;//指向具备拥有权对象的指针 }; };//namespace stl
//以下的一个版本是参考<<C++标准程序库>>(The C++ Standard Library) //Nicolai M.Josuttis 著 侯捷 孟岩 译 2002年9月 //一书 P222 6.8 提出的具备reference的auto_ptr的观点所做的一个版本 //ref auto_ptr: namespace ref { template<class T> class auto_ptr { public: explicit auto_ptr(T * p = NULL):_ptr(p),_count(new unsigned long(1)){} public: auto_ptr(auto_ptr<T>& y):_ptr(y._ptr),_count(y.addref()){}//增加引用计数 auto_ptr<T>& operator=(auto_ptr<T>& y) { if(this!=&y) { if(_ptr!=y._ptr)//是否同一个对象 { release();//释放自己原来的拥有权,这一步 _ptr = y._ptr; _count = y.addref();//增加引用计数 } } return (*this); } ~auto_ptr() { release();//释放拥有权 }
T& operator*() const { return (*_ptr); }
T *operator->() const { return (_ptr); }
unsigned long * addref(void)//增加引用计数 { ++(*_count); return (_count); }
private: void release(void) { if(--(*_count)==0)//减少引用计数并测试引用计数是否为0 { delete _ptr; delete _count; } _count = NULL;//释放引用计数器 _ptr = NULL;//释放拥有权 }
private: T * _ptr;//引用对象指针 unsigned long * _count;//引用计数器指针 }; };//namespace ref
//以上3个版本都是仿照现在比较大众化的被普遍接受的auto_ptr行为的 //简单实现. //在应用上,用具备引用计数的auto_ptr的是比较好的.
//对于auto_ptr的实现还有许多方法,特别是可以依据在不同的应用场合 //实现不同的版本以改变auto_ptr的行为,让它更适合于我们的应用. //如在自己的类库中完全可以用基类来做引用计数从而实现安全的 //具备引用计数的auto_ptr //又如可以用template<>的方法为要装载的类加一个引用计数来实现 //具备引用计数的auto_ptr
//the end.
#endif //AUTO_PTR__H__
//以下是VC6下的测试程序
//dog.h
#ifndef DOG__H__ #define DOG__H__
#include <iostream> #include <string>
//测试类 class dog { public: dog(std::string name = "NoName"):_name(name) { std::cout<<"dog::dog()"<<std::endl; }
~dog() { std::cout<<"dog::~dog()"<<std::endl; }
public: void bark(void) { std::cout<<_name<<" always bark at rose."<<std::endl; }
public: void Name(const std::string& name) { _name = name; }
std::string Name(void) { return _name; }
private: std::string _name; };
#endif //DOG__H__
//main.cpp
#include <iostream> #include <string>
#include "auto_ptr.h" #include "dog.h"
///////////////////////////////////////// //test vc auto_ptr void test_vc_fun(void) { std::cout<<"=== test vc auto_ptr ==="<<std::endl;
vc::auto_ptr<dog> ptom(new dog("Tom"));
{ vc::auto_ptr<dog> pjack(ptom); ptom = pjack; //1. pjack->Name("Jack"); pjack->bark(); pjack->Name("Tom"); } ptom->bark();//因为有1.=>successful,如果去掉1.=>error }
///////////////////////////////////////// //test stl auto_ptr void test_stl_fun(void) { std::cout<<"=== test stl auto_ptr ==="<<std::endl;
stl::auto_ptr<dog> ptom(new dog("Tom"));
{ stl::auto_ptr<dog> pjack(ptom); pjack->Name("Jack"); pjack->bark(); } //ptom->bark();//error }
///////////////////////////////////////// //test ref auto_ptr void test_ref_fun(void) { std::cout<<"=== test ref auto_ptr ==="<<std::endl;
ref::auto_ptr<dog> ptom(new dog("Tom"));
{ ref::auto_ptr<dog> pjack(ptom); pjack->Name("Jack"); pjack->bark(); }
ptom->bark();//successful }
void main(void) { std::cout<<"Hello,the world!"<<std::endl; test_vc_fun(); test_stl_fun(); test_ref_fun(); }
//the end

|