• 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.
        };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    __allocator_base是__gnu_cxx::new_allocator<_Tp>别名

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

    类模板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(); }
        };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    可以看到,在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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在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)...); }
    
    • 1
    • 2
    • 3

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

    template<typename _Up>
    	void destroy(_Up* __p) { __p->~_Up(); }
    
    • 1
    • 2
  • 相关阅读:
    Vim的使用
    3分钟了解Kfaka
    Dephi2007以任意字符串分隔字符
    kubectl 声明式资源管理方式
    java计算时间差 (日时分秒)
    Websocket的基本认识、使用与封装
    快手本地生活服务商系统怎么操作?
    C++ Primer学习笔记-----第三章:字符串、向量、数组
    鲜花商城管理系统
    任职超18年,Go团队技术主管Russ Cox官宣卸任!
  • 原文地址:https://blog.csdn.net/qq_45088122/article/details/134504698