实习满2个月了.谨以此文缅怀本来应该是我最后一个暑假却用来实习的暑假.T_T(楼主强烈声明,实习生活很nice,前面只是吐槽,请无视)
入正题,循惯例,上图先:
简单来看,vector是继承_Vector_base,这里可以说分为两层去实现,在_Vector_base当中封装了跟内存分配相关的操作,如_M_allocate(),_M_deallocate()等,在_Vector_base当中有一个内置的结构,叫做_Vector_impl,他包含了3个指针,分别指向内存区域的起始,结束和当前使用到.这个就是vector的实现,所有的操作都是围绕在这3个指针来展开的,简单清晰._M_allocate(),_M_deallocate()其实就是对allocator申请(allocator())和释放(deallocator())接口的封装.
看侯捷兄的源码剖析的时候,最开始讲的就是allocator,SGI的STL使用的allocator是用了内存池的技术,在分配的效率上可能会高一些.在GCC的库实现当中,默认使用的allocator是最最简单的new allocator,不使用带内存池的allocator原因可以在这里找到http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt04ch11.html ,GCC库当中其实提供了相当多的allocator,有机会再深入学习一下
pointer的定义如下
typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template
rebind<_Tp>::other _Tp_alloc_type;
typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer
pointer;
由于vector不是侵入式的容器,所以rebind<_Tp>其实是无关紧要,侵入式的容器主要是讲申请的内存结构跟T的关系,举例来说,vector<T>申请的内存就是T的数组,这个是没有变化的,但是对于像list<T>这样的容器,我们申请内存的时候除了主要类型T之外,我们还需要额外的两个指针,分别指向前导结点的后续结点,这样的行为可以想象成我们需要的内存被侵入,加了两个指针(总体就是T加上额外2个指针),但是我们传入模板参数的时候使用的是T,与2个额外的指针并没有什么关系.这里就需要rebind这个东西,把我们需要申请的类型重新进行绑定.加入额外的信息.__alloc_traits<>::pointer根据allocator萃取出相应的指针类型.
与C++11相关的一些改动主要是:
加入move构造函数,针对右值引用的构造优化,如
#ifdef __GXX_EXPERIMENTAL_CXX0X__
_Vector_impl(_Tp_alloc_type&& __a)
: _Tp_alloc_type(std::move(__a)),
_M_start(0), _M_finish(0), _M_end_of_storage(0)
{ }
#endif
#ifdef __GXX_EXPERIMENTAL_CXX0X__
_Vector_base(_Tp_alloc_type&& __a)
: _M_impl(std::move(__a)) { }
_Vector_base(_Vector_base&& __x)
: _M_impl(std::move(__x._M_get_Tp_allocator()))
{ this->_M_impl._M_swap_data(__x._M_impl); }
_Vector_base(_Vector_base&& __x, const allocator_type& __a)
: _M_impl(__a)
{
if (__x.get_allocator() == __a)
this->_M_impl._M_swa