本篇是为了帮助理解这篇:
No.9:C++ vector成员函数实现[持续更新]zhuanlan.zhihu.com内存分配相关的内容,而又防止太琐碎,所以单独开的,也是一篇学习笔记。其中有几块内容是比较困惑的,展开学习一下。
这块有点背景要讲,比较绕,尽量说清楚,多想几遍
在<stl_vector>中,如下代码片段,其中_Alloc=std::allocator<_Tp>,并且在_Vector_impl中封装了__alloc_traits的allocate和deallocate函数,用于分配释放内存
嵌套了两层
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;
struct _Vector_impl
: public _Tp_alloc_type
因此首先看下__alloc_traits
[1] __alloc_traits
__alloc_traits在ext/alloc_traits中定义,类继承自std::allocator_traits
/**
* @brief Uniform interface to C++98 and C++11 allocators.
* @ingroup allocators
*/
template<typename _Alloc>
struct __alloc_traits
#if __cplusplus >= 201103L
: std::allocator_traits<_Alloc>
#endif
- 其中的静态成员::template rebind<_Tp>::other在154-156行,如下
template<typename _Tp>
struct rebind
{ typedef typename _Alloc::template rebind<_Tp>::other other; };
可见,实际是_Alloc::template rebind<_Tp>::other,(在下面知就是allocator<_Tp1>)
- 成员函数
static pointer
allocate(_Alloc& __a, size_type __n)
{ return __a.allocate(__n); }
static void deallocate(_Alloc& __a, pointer __p, size_type __n)
{ __a.deallocate(__p, __n); }
实际上是用第一个参数作为函数来调用,而其中的_Alloc就是下面[2]介绍的,所以要看下这个变量的三个同名函数的实现
[2]std::allocator<_Tp>其中_Tp为内置或自定义类型
其中的泛型,具体化为std::allocator<_Tp>时,研究下一些具体的实现策略
定义在<bits/allocator>中
- 66行-97行allocator具体化
- 100行-142行allocator继承自__allocator_base
定义在25行-55行,是new_allocator的类型别名,下面[4]中探究
/** @file bits/c++allocator.h
* This is an internal header file, included by other library headers.
* Do not attempt to use it directly. @headername{memory}
*/
#ifndef _GLIBCXX_CXX_ALLOCATOR_H
#define _GLIBCXX_CXX_ALLOCATOR_H 1
#include <ext/new_allocator.h>
#if __cplusplus >= 201103L
namespace std
{
/**
* @brief An alias to the base class for std::allocator.
* @ingroup allocators
*
* Used to set the std::allocator base class to
* __gnu_cxx::new_allocator.
*
* @tparam _Tp Type of allocated object.
*/
template<typename _Tp>
using __allocator_base = __gnu_cxx::new_allocator<_Tp>;
}
#else
// Define new_allocator as the base class to std::allocator.
# define __allocator_base __gnu_cxx::new_allocator
#endif
- 144行-166行重载一些运算符
- rebind在119行-121行
template<typename _Tp1>
struct rebind
{ typedef allocator<_Tp1> other; };
[3]allocator_traits<_Alloc>的实现
这个变量可以定位到<bits/alloc_traits>,下面都是围绕这个头文件说明源码
45行到76行都是结构体__allocator_traits_base的定义
82行到360行是结构体allocator_traits的定义
363行到486行是结构体allocator_traits的部分具体化
这个没什么实质内容
[4]new_allocator探究
截取下面这段函数研究下
pointer
address(reference __x) const _GLIBCXX_NOEXCEPT
{ return std::__addressof(__x); }
const_pointer
address(const_reference __x) const _GLIBCXX_NOEXCEPT
{ return std::__addressof(__x); }
// NB: __n is permitted to be 0. The C++ standard says nothing
// about what the return value is when __n == 0.
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)));
}
// __p is not permitted to be a null pointer.
void
deallocate(pointer __p, size_type)
{ ::operator delete(__p); }
size_type
max_size() const _GLIBCXX_USE_NOEXCEPT
{ return size_t(-1) / sizeof(_Tp); }
可见分配内存最后还是用::operatornew