关于容器与空间分配

容器本质上的作用就是对数据的管理,整体来说就是对数据的增、删、修改;但是结合了计算机的空间属性,就又需要进行一次扩展,也就是对于计算机空间的管理:申请与释放;

关于new操作原理:

对于一个元素的话,整个过程可以参考new的过程,且STL默认的空间分配器就是以new作为基础进行实现,new的话,直接使用它会申请需要的空间并调用对象的构造函数并返回构造好对象的空间地址;他是分为两个过程的,一个过程是对空间的申请,另外一个过程是对申请到的空间的对象构造;在C++中分别是operator new与placement new;

容器基于这样的空间分配方式以及对象构造方式进行对数据的存储以及管理;

STL空间分配器:

stl默认的空间分配器为std::allocator;该类为一个模板类,对应的源码位置为libstdc++-v3/include/bits/allocator.h;该模板类继承另外一个模板类,__allocator_base,该基类为一个宏,在libstdc++-v3/include/bits/c++allocator.h中定义,最终该基类指向/libstdc++-v3/include/ext/new_allocator.h;里面有几个接口,这些接口基本原理就是operator new和placement new的具体使用;而rebind则是该空间分配器绑定另外一个类型进行返回。该空间分配器allocator接口的作用就是基于_Tp作为基本单元,而后申请需要单位数的空间;该类源码如下:

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* = 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); }

#if __cplusplus >= 201103L
      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(); }
#else
      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 402. wrong new expression in [some_] allocator::construct
      /* placement new函数,也就是调用构造函数去初始化申请到的空间 */
      void 
      construct(pointer __p, const _Tp& __val) 
      { ::new((void *)__p) _Tp(__val); }

      /* 调用析构函数 */
      void 
      destroy(pointer __p) { __p->~_Tp(); }
#endif
    };

    /* 利用template模板去判断两个分配器是否是相同的分配器 */
  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;
    }

这样,通过对_Tp的类型绑定,在申请内存的时候直接申请需要的单位即可;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值