1.概述
标准库各类容器的操作过程往往需要空间分配,空间分配和释放需要分配器的支持。以下介绍标准库默认分配器实现。
2.默认分配器
基类部分
using std::size_t;
using std::ptrdiff_t;
template<typename _Tp>
inline _Tp* __addressof(_Tp& __r) _GLIBCXX_NOEXCEPT
{
return reinterpret_cast<_Tp*>(&const_cast<char&>(reinterpret_cast<const volatile char&>(__r)));
}
// 类型为_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;
};
typedef std::true_type propagate_on_container_move_assignment;
// 默认构造
new_allocator() _GLIBCXX_USE_NOEXCEPT { }
// 拷贝构造
new_allocator(const new_allocator&) _GLIBCXX_USE_NOEXCEPT { }
// 普通构造--_Tp,_Tp1是相同类型
// 拷贝构造--_Tp,_Tp1是不同类型
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); }
// 分配功能
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)));// 通过::operator new实现空间分配
}
// 释放功能
void deallocate(pointer __p, size_type)
{ ::operator delete(__p); }// 通过::operator delete实现空间释放
size_type max_size() const _GLIBCXX_USE_NOEXCEPT
{ return size_t(-1) / sizeof(_Tp); }// 一次最多可分配的对象数目
// 模板参数1:类型参数
// 模板参数2:可变模板参数
// 函数参数1:类型指针
// 函数参数2:模板参数包,对包内每个元素添加&&修饰
// 函数内通过::new((void *)__p) _Up(std::forward<_Args>(__args)...);实现在指定位置执行构造函数。采用了模板参数包的完美转发。
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(); }
};
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; }
默认分配器
// 模板特化--特化就是模板参数类型做了指定或做了修饰(这个修饰会影响其可匹配到的范围)
template<>
class allocator<void>
{
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef void* pointer;
typedef const void* const_pointer;
typedef void value_type;
template<typename _Tp1>
struct rebind {
typedef allocator<_Tp1> other;
};
typedef true_type propagate_on_container_move_assignment;
};
template<typename _Tp>
using __allocator_base = __gnu_cxx::new_allocator<_Tp>;
// 用于分配类型_Tp元素的分配器
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;
};
typedef true_type propagate_on_container_move_assignment;
// 默认构造
allocator() throw() { }
// 拷贝构造
allocator(const allocator& __a) throw() : __allocator_base<_Tp>(__a) { }
// 普通构造--_Tp1和_Tp类型不同时
// 拷贝构造--_Tp1和_Tp类型相同时
template<typename _Tp1>
allocator(const allocator<_Tp1>&) throw() { }
// 析构
~allocator() throw() { }
};
// 支持==,!=运算符
template<typename _T1, typename _T2>
inline bool operator==(const allocator<_T1>&, const allocator<_T2>&)
{ return true; }
template<typename _Tp>
inline bool operator==(const allocator<_Tp>&, const allocator<_Tp>&)
{ return true; }
template<typename _T1, typename _T2>
inline bool operator!=(const allocator<_T1>&, const allocator<_T2>&)
{ return false; }
template<typename _Tp>
inline bool operator!=(const allocator<_Tp>&, const allocator<_Tp>&)
{ return false; }
以上综合应用了各类语言的能力,如类型别名,::operator new
,::operator delete
,placement new
,析构,模板特化,可变模板参数,模板参数包转发,完美转发,类型强制转换等。