好记性不如铅笔头

C && C++, C++ STL, 编程

C++ STL读书笔记:allocator

备注:

本读书笔记基于侯捷先生的《STL源码剖析》,截图和注释版权均属于原作者所有。
本读书笔记中的源码部分直接拷贝自SGI-STL,部分代码删除了头部的版权注释,但代码版权属于原作者
小弟初看stl,很多代码都不是太懂,注释可能有很多错误,还请路过的各位大牛多多给予指导。

std::allocator

我们以vector为例子,看下它的默认的allocator是什么。我们首先看下 vector ,里面什么也没有,但是有一行:

#include <bits/stl_vector.h>

然后我们再看下 stl_vector.h ,部分内容如下:

  template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
    class vector : protected _Vector_base<_Tp, _Alloc>
     。。。。。

通过这个我们可以知道vector默认的allocator是std::allocator,也可以大致的推断出其他的容器应该也是这个。

我们打开 allocator.h ,部分内容如下:

// Define the base class to std::allocator.
#include <bits/c++allocator.h>

_GLIBCXX_BEGIN_NAMESPACE(std)

  template<typename _Tp>
    class allocator: public __glibcxx_base_allocator<_Tp>
     。。。。

通过这里我们可以知道std::allocator就在这个文件中,继承自【 __glibcxx_base_allocator 】。这里我们先跳过这个文件,继续include。

我们打开 c++allocator.h ,部分内容如下:

#include <ext/new_allocator.h>
#define __glibcxx_base_allocator  __gnu_cxx::new_allocator

这里我们知道【 __glibcxx_base_allocator 】其实就是【 __gnu_cxx::new_allocator 】,继续,
打开 new_allocator.h ,部分内容如下:

_GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
  template<typename _Tp>
    class new_allocator
    {
     。。。。。

看到这里我们就可以大致的知道stl中的默认allocator的继承关系和代码位置了。然后我们开始注释代码(去掉了头部版权注释):

new_allocator.h:

#include <new>
#include <bits/functexcept.h>
#include <bits/move.h>
//在命名空间__gnu_cxx中
_GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)

  using std::size_t;
  using std::ptrdiff_t;

  /**
   *  @brief  An allocator that uses global new, as per [20.4].
   *  @ingroup allocators
   *
   *  This is precisely the allocator defined in the C++ Standard. 
   *    - all allocation calls operator new
   *    - all deallocation calls operator delete
   */
//《STL源码剖析》P43页对此作了简要介绍,根据C++标准,如下typedef和函数是必须定义的。
  template<typename _Tp>
    class new_allocator
    {
    public:
      typedef size_t     size_type;
      typedef ptrdiff_t  difference_type;
      typedef _Tp*       pointer;
      typedef const _Tp* const_pointer;
      typedef _Tp&       reference;
      typedef const _Tp& const_reference;
      typedef _Tp        value_type;


      template<typename _Tp1>
        struct rebind
        { typedef new_allocator<_Tp1> other; };

      new_allocator() throw() { }

      new_allocator(const new_allocator&) throw() { }

      template<typename _Tp1>
        new_allocator(const new_allocator<_Tp1>&) throw() { }

      ~new_allocator() throw() { }

      pointer
      address(reference __x) const { return &__x; }

      const_pointer
      address(const_reference __x) const { return &__x; }

      // NB: __n is permitted to be 0.  The C++ standard says nothing
      // about what the return value is when __n == 0.
      pointer
      allocate(size_type __n, const void* = 0)
      { 
				 if (__n > this->max_size())
				   std::__throw_bad_alloc();
				//申请空间时直接调用operator new,也就是我们平常使用的new操作符,申请空间
				 return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
      }

      // __p is not permitted to be a null pointer.
      void
      deallocate(pointer __p, size_type)
      { ::operator delete(__p); }//申请空间时直接调用operator delete,也就是我们平常使用的delete操作符,释放空间

      size_type
      max_size() const throw() 
      { return size_t(-1) / sizeof(_Tp); }

      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 402. wrong new expression in [some_] allocator::construct
      void 
      construct(pointer __p, const _Tp& __val) 
      { ::new((void *)__p) _Tp(__val); }//调用placement new,相当于在已有内存上直接调用构造函数

#ifdef __GXX_EXPERIMENTAL_CXX0X__
      template<typename... _Args>
        void
        construct(pointer __p, _Args&&... __args)
 { ::new((void *)__p) _Tp(std::forward<_Args>(__args)...); }
#endif

      void 
      destroy(pointer __p) { __p->~_Tp(); }//直接调用实例的析构函数
    };

  template<typename _Tp>
    inline bool
    operator==(const new_allocator<_Tp>&, const new_allocator<_Tp>&)
    { return true; }
  
  template<typename _Tp>
    inline bool
    operator!=(const new_allocator<_Tp>&, const new_allocator<_Tp>&)
    { return false; }


_GLIBCXX_END_NAMESPACE

 

发表评论

17 − 6 =

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据