STL源码阅读(2)–allocator::rebind

STL源码阅读(2)–allocator::rebind

经过前面的了解,我想应该可以正式进入STL的容器实现的阅读了,ok那就先来看看vector的实现。vector的实现代码在bits/stl_vector.h中,可以看到的是一个类_Vector_base

template<typename _Tp, typename _Alloc>
    struct _Vector_base
    {
      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;

类中首先是定义__gnu_cxx::__alloc_traits<_Alloc>::template
rebind<_Tp>::other的别名,what?rebind是什么东西?一开始便看不懂了。好吧,阅读容器实现前还是先搞懂rebind是个什么鬼。

1.来源

从_gnu_cxx::__alloc_traits<_Alloc>::template
rebind<_Tp>::other看rebind是来自模板类__alloc_traits,该类在ext/alloc_atraits.h文件中定义

  #if __cplusplus >= 201103L
  typedef std::allocator_traits<_Alloc>           _Base_type;
   template<typename _Tp>
      struct rebind
      { typedef typename _Base_type::template rebind_alloc<_Tp> other; };
  #else
    template<typename _Tp>
      struct rebind
      { typedef typename _Alloc::template rebind<_Tp>::other other; };

从上可以看出rebind来自_Alloc类,在上一篇中说明了_Alloc对应allocator类型有多种,这里以std::allocator为例,看ext/new_allocator.h中rebind定义。

template<typename _Tp>
    class new_allocator
    {
    public:
      template<typename _Tp1>
        struct rebind
        { typedef new_allocator<_Tp1> other; };

这里可以看出rebind是重新将new_allocator(std::allocator)分配的类型绑定为_Tp1类型。但这样有什么用,std::allocator<_Tp>::rebind<_Tp1>不是等同于std::allocator<_Tp1>吗?直接用std::allocator<_Tp1>不就行吗?
为什么呢?

2.为什么定义rebind

继续往下看vector的实现,vector继承自_Vector_base

template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
    class vector : protected _Vector_base<_Tp, _Alloc>
    {
      typedef typename _Alloc::value_type                _Alloc_value_type;
      __glibcxx_class_requires(_Tp, _SGIAssignableConcept)
      __glibcxx_class_requires2(_Tp, _Alloc_value_type, _SameTypeConcept)
      
      typedef _Vector_base<_Tp, _Alloc>			 _Base;
      typedef typename _Base::_Tp_alloc_type		 _Tp_alloc_type;
      typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type>  _Alloc_traits;

类vector模板默认指定的分配器是std::allocator,分配的类型为_Tp,模板参数传递给_Vector_base分配类型也是_Tp。 因为_Vector_base模板中rebind的类型与模板参数相同,所以最终rebind的类型也是_Tp。这个rebind的类型没有改变过,rebind好像没什么意义啊!怎么回事?

带这个疑问去查看list容器的实现:

template<typename _Tp, typename _Alloc>
//_List_base类
    class _List_base
    {
    protected:
     
      typedef typename _Alloc::template rebind<_List_node<_Tp> >::other
        _Node_alloc_type;

      typedef typename _Alloc::template rebind<_Tp>::other _Tp_alloc_type;
   //   list类:
 template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
    class list : protected _List_base<_Tp, _Alloc>
    {
      // concept requirements
      typedef typename _Alloc::value_type                _Alloc_value_type;
      __glibcxx_class_requires(_Tp, _SGIAssignableConcept)
      __glibcxx_class_requires2(_Tp, _Alloc_value_type, _SameTypeConcept)

      typedef _List_base<_Tp, _Alloc>                    _Base;
      typedef typename _Base::_Tp_alloc_type		 _Tp_alloc_type;
      typedef typename _Base::_Node_alloc_type		 _Node_alloc_type;

list类同类vector模板默认指定的分配器是std::allocator,分配的类型为_Tp,模板参数传递给_Vector_base分配类型也是_Tp。
在_List_base类中,要为list节点分配空间,list节点是一个<_List_node<_Tp>类型数据结构,使用_Tp去分配无法正确分配。

如何分配这个数据结构呢?
ok,类型不是<_List_node<_Tp>吗,使用std::allocator<_List_node<_Tp>不是就解决了吗?
但是模板指定的分配器是std::allocator<_Tp>,怎么办?
那就增加一个模板参数用于指定分配<_List_node<_Tp>啊,ok这样好像可以哎。这样有两个问题:多了一个模板参数,两个alloc模板参数指定的分配器要确保一致。
更好的方法是只指定一个分配器,就实现两种类型的分配。
rebind就是这样的一个作用,可以直接指定另一种类型的分配。 _Alloc::template rebind<_List_node<_Tp> >::other指定分配类型为<_List_node<_Tp> 。

3.总结

综上,rebind并不是没有作用,只是在vector中不需要用到第二种类型的分配。当容器需要对不同类型使用同一分配策略时,rebind的意义就体现出来。
:有一个容器类MyVector, 它用的是Allocator_A内存分配器,这个容器类很有可能需要double类型的分配器,而且要求对int和double类型的内存分配策略是一样的。

总之,rebind可以重新指定分配器分配空间的类型,实现了对不同类型使用同一种内存分配策略的要求。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值