大部分人在学习STL源码的时候,都会参考侯捷老师的《STL源码剖析》,在第二章介绍分配器的时候,出现过rebind的身影:
这段代码神秘的出现在了这里,然后了无后续,相信给很多人造成了STL修仙练气期的心里阴影。
VC++ STL rebind
翻阅MSDN的文档介绍,rebind是使得一种类型的对象分配器可以为另一种类型的对象分配内存的工具类,此类可用于为与所实现的容器的元素类型不同的类型分配内存。这是一个模板类,模板参数为其他类型,其唯一目的是在给定类型allocator<T>时,定义了另外一个类型allocator<U>,并给其一个别名rebind::other。[MSDN rebind]
上面一段话有点拗口,用大白话说就是:我们在定义容器的时候,可以给容器指定分配器类型,一般使用的是默认的分配器std::allocator,如定义vector<int>,其分配器为allocator<int>, 我们可以通rebind<double>::other(其实就是allocator<double>)来定义一个double类型的分配器。
看如下示例,就能明白上面说的是啥意思:
#include <memory>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef vector<int>::allocator_type IntAlloc;
int main()
{
vector<int> v1;
IntAlloc v1Alloc;
//利用v1.get_allocator()拷贝构造一个char类型分配器
IntAlloc::rebind<char>::other::pointer pszC =
IntAlloc::rebind<char>::other(v1.get_allocator()).allocate(1, (void*)0);
int* pInt = v1Alloc.allocate(10);
}
当然,这个例子纯属吃饱了撑着,只是为了告诉你rebind在干什么。
std::list中rebind实例
rebind在很多容器中都有应用,例如定义一个list<int> li ,其分配器类型为std::allocator<int>,但是诸位应该知道,list里面存储的是list_node类型,而非int类型,这个时候,就需要将分配器rebind到list_node类型,是不是很神奇的设计。其他的诸如map,set等容器,也有类似的需求。
如下为list源码中,rebind相关的片段:
template <class _Ty>
class allocator {
//……
template <class _Other>
struct _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS rebind {
using other = allocator<_Other>;
};
//……
};
list插入节点的时候,使用的是_AlNode(allocator node),这个就是list定义时的分配器allocator<T>,rebind后的分配器allocator<list_node>。
using _Node = _List_node<_Ty, typename allocator_traits<_Alloc>::void_pointer>;
using _Alnode = _Rebind_alloc_t<_Alloc, _Node>;
template <class... _Valty>
_Nodeptr _Emplace(const _Nodeptr _Where, _Valty&&... _Val) { // insert element at _Where
size_type& _Mysize = _Mypair._Myval2._Mysize;
if (_Mysize == max_size()) {
_Xlength_error("list too long");
}
_List_node_emplace_op2<_Alnode> _Op{_Getal(), _STD forward<_Valty>(_Val)...};
++_Mysize;
return _Op._Transfer_before(_Where);
}