很久没上来写东西了,最近认真学习了一下C++,发现真是博大精深,以前可以说是白痴一个。当读到Template的时候,确实很好奇,因为自己确实想彻底弄清楚模板这块。看完后就想找个地方试试看自己看懂了没有,很自然的就想到了STL。
STL确实是一个很实用的东西,最重要的是他写得通用而且已经作为了C++的标准放入了所有的C++ distribution中。想看看自己模板学好了没有,就去读STL。以前也想过研究这个library,后来发现自己被一大堆的”<“和”>”彻底打懵了。现在再钻进去看,觉得清楚多了。候先生的《STL源码剖析》确实是好书,可惜电子版只有前面四章,托国内同学买也未果,所以就有了这个“STL 研读笔记系列” -- 自己把感兴趣的部分读懂,然后做做笔记。
一开始当然要从最简单的template class开始。什么最简单?vector? list? 我觉得是auto_ptr。 这个auto_ptr是一个非常简单的smart pointer类。说它简单是因为它只具有自动释放内存(析构)的功能,没有对象指针引用计数的功能。好,废话少说,这就来看看这个类。
//一个wrapper class,这个类模拟了auto_ptr的reference类型。可以被一个传回auto_ptr值的函数赋值。
template<typename _Tp1> struct auto_ptr_ref
{
_Tp1* _M_ptr;explicit
auto_ptr_ref(_Tp1* __p): _M_ptr(__p) { }
};
//下面这个是真正的auto_ptr模板类。它唯一的成员数据就是一个模板类型的指针,这个是真正指向需要“保护”的对象的指针
template<typename _Tp> class auto_ptr
{
private:
_Tp* _M_ptr; public:
typedef _Tp element_type;
//构造函数,explicit表示这是一个禁止constructor conversion的构造函数,传入的参数必须是_Tp*类型
explicit auto_ptr(element_type* __p = 0) throw() : _M_ptr(__p) { }
//同类型拷贝构造函数,参数是另外一个auto_ptr,但是这个auto_ptr要释放自己所包含的指针。正式这个move而不是copy的语义导致了“千万不要使用类型为auto_ptr的容器”!
//这个模板类比较特殊,数据是指针,所以允许不同类型之间的拷贝
auto_ptr(auto_ptr& __a) throw() : _M_ptr(__a.release()) { }
//不同类型的拷贝构造函数,同样也是move的办法
template<typename _Tp1> auto_ptr(auto_ptr<_Tp1>& __a) throw() : _M_ptr(__a.release()) {} //同类型的auto_ptr赋值操作符,__a释放自己包含的指针,本模板类用reset更新自己的指针为__a的指针
auto_ptr& operator=(auto_ptr& __a) throw()
{
reset(__a.release());
return *this;
}
//不同类型的auto_ptr赋值操作符
template<typename _Tp1> auto_ptr& operator=(auto_ptr<_Tp1>& __a) throw()
{
reset(__a.release());
return *this;
}
//析构函数,当auto_ptr走出scope的时候,自己释放对象。但是这里的局限就是delete,而不支持释放数组对象数组的delete []。所以决定了auto_ptr只能hold单一指针。
~auto_ptr() {delete _M_ptr;}
//重载dereference操作符。
element_type& operator* const throw()
{
_GLIBCXX_DEBUG_ASSERT(_M_ptr != 0);
return *_M_ptr;
}
//重载“member access from a pointer” 操作符。注意这里的返回值和上面的dereference返回值不同,这里返回的是成员指针。当需要调用auto_ptr->func()的时候,实际上是调用了 auto_ptr->()->func(),这个是C++内部处理的。
element_type* operator->() const throw()
{
_GLIBCXX_DEBUG_ASSERT(_M_ptr !=0 );
return _M_ptr;
}
//获取成员指针函数
element_type* get() const throw() {return _M_ptr; }
//获取成员指针函数,同时将成员指针清零
element_type* release() throw()
{
element_type* __tmp = _M_ptr;
_M_ptr = 0;
return __tmp;
}
//释放成员指针所指向的对象,同时给成员指针赋新值
void reset(element_type* __p = 0) throw()
{
if (__p != _M_ptr)
{
delete _M_ptr;
_M_ptr = __p;
}
}
//从auto_ptr_ref构造auto_ptr的构造函数
auto_ptr(auto_ptr_ref<element_type> __ref) throw() : _M_ptr(__ref._M_ptr) { }
//从auto_ptr_ref的赋值操作符,包含self-assignment 检查。前面的赋值操作符没有这个检查,因为当时只是指针的赋值,不涉及内存的释放。
auto_ptr& operator=(auto_ptr_ref<element_type> __ref) throw()
{
if (__ref._M_ptr != this->get())
{
delete _M_ptr;
_M_ptr = __ref._M_ptr;
}
return *this;
}
//本auto_ptr到其他任意类型auto_ptr_ref的conversion操作符重载
template<typename _Tp1>
operator auto_ptr_ref<_Tp1>() throw()
{ return auto_ptr_ref<_Tp1>(this->release()); }
//本auto_ptr到其他任意类型的auto_ptr的conversion操作符重载
template<typename _Tp1>
operator auto_ptr<_Tp1>() throw()
{ return auto_ptr<_Tp1>(this->release()); }
};
好了,写到这里自己也温习了一遍,也收获不小,下次再选一个稍微复杂一点的来分析一下。