C++学习(2):分配器allocator

new和operator new

new是关键字,new 操作符的执行过程:

  1. 调用operator new分配内存;
  2. 调用构造函数在operator new返回的内存地址处生成类对象;

operator new是一个函数,可以被重载,通过重载它,可以改变new操作符的功能。功能类似malloc,如果类中没有重载operator new,那么调用的就是全局的::operator new来从堆中分配内存。

new将内存分配和对象构造组合在一起。
一般情况下,将内存分配和对象构造组合在一起会导致不必要的浪费。可能创建了一些永远不会用到的对象,或者使用到的元素被重复赋值两次。
allocator类帮助我们将内存分配和对象构造分离,可以分配大量内存,只有在真正需要的时候才执行对象创建操作。

类模板allocator

继承自__allocator_base,只定义了构造和析构函数。

template<typename _Tp>
    class allocator: public __allocator_base<_Tp>
    {
   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 allocator<_Tp1> other; };

#if __cplusplus >= 201103L
      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 2103. std::allocator propagate_on_container_move_assignment
      typedef true_type propagate_on_container_move_assignment;

      typedef true_type is_always_equal;
#endif

      allocator() throw() { }

      allocator(const allocator& __a) throw()//throw()表示该函数不会抛出异常
      : __allocator_base<_Tp>(__a) { }

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

      ~allocator() throw() { }

      // Inherit everything else.
    };

__allocator_base是__gnu_cxx::new_allocator<_Tp>别名

 template<typename _Tp>
    using __allocator_base = __gnu_cxx::new_allocator<_Tp>;

类模板new_allocator

除了析构函数和构造函数之外,还定义了allocate、deallocate分配和释放内存、construct、destroy构造和析构对象。

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; };

#if __cplusplus >= 201103L
      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 2103. propagate_on_container_move_assignment
      typedef std::true_type propagate_on_container_move_assignment;
#endif

      new_allocator() _GLIBCXX_USE_NOEXCEPT { }

      new_allocator(const new_allocator&) _GLIBCXX_USE_NOEXCEPT { }

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

      ~new_allocator() _GLIBCXX_USE_NOEXCEPT { }

      pointer address(reference __x) const _GLIBCXX_NOEXCEPT
      { return std::__addressof(__x); }

      const_pointer address(const_reference __x) const _GLIBCXX_NOEXCEPT
      { return std::__addressof(__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* = static_cast<const void*>(0))
      {
		if (__n > this->max_size())
	  		std::__throw_bad_alloc();
		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);
      }

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

      template<typename _Up, typename... _Args>
	void construct(_Up* __p, _Args&&... __args)
	{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }

      template<typename _Up>
	void destroy(_Up* __p) { __p->~_Up(); }
    };

可以看到,在allocate和deallocate中分别调用了::operator new和::operator delete,实现分配和释放内存。::运算符被称为作用域解析运算符,通过加上这个前缀,告诉编译器在全局命名空间中查找该类型。

pointer allocate(size_type __n, const void* = static_cast<const void*>(0))
{
	if (__n > this->max_size())
	std::__throw_bad_alloc();
	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);
}

在construct()调用了构造函数,使用placement new在指定内存中构建对象(定位new允许我们在一个特定的、预先分配的内存地址上构造对象,placement new是一种特殊的operate new),并使用std::forward转发模板参数到构造函数。

template<typename _Up, typename... _Args>
	void construct(_Up* __p, _Args&&... __args)
	{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }

在destroy()中调用了析构函数。

template<typename _Up>
	void destroy(_Up* __p) { __p->~_Up(); }

你可能感兴趣的:(c++,学习,java)