STL库rebind原理详解

我最近发现国内中文网站上对于STL的一些魔法基本未做任何介绍,基本上都是不知所云的一概而过。因此接下来详细分析一些比较复杂的STL代码,本篇文章分析rebind,所有代码均摘自allocator::rebind模板类

rebind 的用法

rebind 用于为与正在实现的容器的元素类型不同的类型分配内存。摘自 这篇 MSDN 文章

例如,给定一个类型为 A 的分配器对象 al,您可以使用以下表达式分配类型为 _Other 的对象:

A::rebind<Other>::other(al).allocate(1, (Other *)0)
  • 1

或者,您可以通过编写类型来命名其指针类型:

A::rebind<Other>::other::pointer
  • 1

还有一种比较合理的解释:

rebind 的意义就在于实现两个不同但两者互相有关的类型(比如类型 T 和 Node类型),使用同一种内存分配方法。
如果抛开 rebind 不提,想要实现上述的意义,容器必须要让 allocator 是同一个模板,问题就出在容器并不关心你的 allocator 是怎么写的,他唯一有关的就是在声明时在 template 中写 alloc = allocator<T>,只知道模板参数名 allocator,而不知道其具体实现,导致没有办法让 T 与 U 的 allocator 是同一个。
于是在 allocator<T> 中创建一个 U 的 allocator,标准中有这样的规定:
对于 allocator<T> 与一个类型 U,allocator<U> 与 allocator<T>::rebind<U>::other 是等价的。
在想使用 allocator<U> 的时候就需要使用 allocator<T>::rebind<U>::other,否则就是用了一个别的 allocator 了。

一个明确的例子:

比如说我们构造一个 std::list<int, myAlloc<int>>,分配器 myAlloc<int> 用于分配 int 类型的对象。但是 std::list<int, myAlloc<int>> 内部实际储存的是节点(list 就是双向链表),因此实际上需要分配某种节点类型(node)的对象。std::list<int, myAlloc<int>> 需要通过策略 myAlloc 来分配节点类型(node)对象,也就是说需要 myAlloc<node>>

比较复杂的应用

位于标准库 stl_list.h 的 _List_base 类有几句非常抽象的话。

typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template
	rebind<_Tp>::other				_Tp_alloc_type;
	
typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type>	_Tp_alloc_traits;

typedef typename _Tp_alloc_traits::template
	rebind<_List_node<_Tp> >:: other _Node_alloc_type;
	
typedef __gnu_cxx::__alloc_traits<_Node_alloc_type> _Node_alloc_traits;

先分析第一句,首先查找 __alloc_traits 模板类,有

template<typename _Alloc, typename = typename _Alloc::value_type>
  struct __alloc_traits{
  ...
template<typename _Tp>
      struct rebind
      { typedef typename _Base_type:: template rebind_alloc<_Tp> other; };
}

因此,
typename __gnu_cxx::__alloc_traits<_Alloc>::template rebind<_Tp>::other
等价于
typename _Base_type::template rebind_alloc<_Tp>
接下来查找 _Base_type 的模板类的定义,得到

typedef std::allocator_traits<_Alloc>           _Base_type;

因此上述语句等价于
std::allocator_traits<_Alloc>::template rebind_alloc<_Tp>
接下来寻找 std::allocator_traits 的定义,该模板类有一个偏特化版本,用于萃取 std::allocator,在该模板类中,有

template<typename _Up>
	using rebind_alloc = allocator<_Up>;

因此,第一句可以看作是
allocator<_Tp>

总结:
typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template rebind<_Tp>::other _Tp_alloc_type;
等价于
allocator<_Tp> _Tp_alloc_type;

第一句话的含义是使用默认分配器 std::allocator 来对 _Tp(通常是 std::list<_Tp>)分配内存。
同理

总结:
typedef typename _Tp_alloc_traits::template rebind<_List_node<_Tp> >:: other _Node_alloc_type;
等价于
allocator<_List_node<_Tp>> _Node_alloc_type;

第三句话的含义是使用默认分配器 std::allocator 来对 _List_node<_Tp>(通常是 std::list<_Tp> 中的节点对象)分配内存。

STL库rebind原理详解-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值