本期主要讲解C++ STL中的内存分配器std::allocator
及其特性萃取器__gnu_cxx::__alloc_traits
。
为防止混淆,规定如下:
allocator
:泛指内存分配器,仅仅是一个术语。std::allocator
:是STL实现的内存分配器类std::allocator
。
更多硬核知识,欢迎关注:
__gnu_cxx::new_allocator
C++的默认的内存分配器std::allocator
,继承至__gnu_cxx::new_allocator
。而 __gnu_cxx::new_allocator
主要完成两个任务:
- 分配对象内存、初始化对象
- 析构对象、释放对象内存
__gnu_cxx::new_allocator
是个空类,没有成员变量,主要有四种成员函数完成上述任务:
allocate
函数,用于分配内存construct
函数,调用已分配内存对象的构造函数destroy
函数,调用析构函数deallocate
函数,用于释放内存
__gnu_cxx::new_allocator
的整体框架大致如下:
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;
};
new_allocator() _GLIBCXX_USE_NOEXCEPT {
}
new_allocator(const new_allocator &) noexcept {
}
template <typename _Tp1>
new_allocator(const new_allocator<_Tp1> &) noexcept {
}
~new_allocator() noexcept {
}
pointer allocate(size_type __n, const void * = static_cast<const void *>(0));
void deallocate(pointer __p, size_type);
size_type max_size() const noexcept;
template <typename _Up, typename... _Args>
void construct(_Up *__p, _Args &&...__args)
noexcept(noexcept(::new ((void *)__p)_Up(std::forward<_Args>(__args)...)));
template <typename _Up>
void destroy(_Up *__p) noexcept(noexcept(__p->~_Up()));
//...
};
allocate
allocate
函数,用于分配大小为__n
个字节内存,返回值是分配所得内存的地址。
- 如果待分配内存大小
__n
大于当前进程最大可用内存,那么就会抛出bad_alloc
异常。 - 再调用
operator new
来分配内存。operator new
对malloc
作了一层简单的封装,等效于malloc
- 将指向
operator new
的返回值类型转换为此次分配对象_Tp
的指针类型。
整个过程如下:
pointer allocate(size_type __n, const void * = static_cast<const void *>(0))
{
if (__n > this->max_size())
std::__throw_bad_alloc();
#if __cpp_aligned_new
if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
{
std::align_val_t __al = std::align_val_t(alignof(_Tp));
return static_cast<_Tp *>(::operator new(__n * sizeof(_Tp), __al));
}
#endif
return static_cast<_Tp *>(::operator new(__n * sizeof(_Tp)));
}
deallocate
deallo