vector和内存池
最近看内存池有关的东西,又回顾了一下之前看C++ Primer时自己写的vector,发现只是对基本的Vector的成员函数进行了重写,最重要的地方也就是分配器用的都是默认的,所以内存分配这块之前就没弄清楚。
template<class _Ty,
class _Alloc = allocator<_Ty> >
class vector
: public _Vector_alloc<_Vec_base_types<_Ty, _Alloc> >
从STL中vector的源码可以看出,vector分为两个部分,一个是参数类型 _Ty,这里的class跟typename是同一个东西,没有区别;还有一个是分配器 _Alloc,默认是allocator< _Ty >,内存池实现就是在这里,自带的分配器只是简单的new一个内存,vector实现的时候,设立三个指针:
private:
std::string *elements; //分配内存的头指针
std::string *first_free; //第一个空闲位置的指针
std::string *cap; //开的内存容量指针
std::allocator<std::string> alloc; //分配器
这样简单的判断size==capacity时,重新分配一个大小是原本两倍的内存,再使用移动赋值将原本的数据迁移到新内存中。
分配器allocator
下面的表格是一个分配器所需实现的内存处理成员函数:
成员函数 | 简介 |
---|---|
allocate | 分配未初始化的存储 (公开成员函数) |
deallocate | 解分配存储 (公开成员函数) |
construct | 在分配的存储构造对象 (公开成员函数) |
destroy | 析构在已分配存储中的对象 (公开成员函数) |
通过实现重载这些成员函数可以实现内存池
allocator::rebind
最近看内存池的实现,发现分配器中有一段代码看不懂:
template <typename U>
struct rebind {
typedef MemoryPool<U> other;
};
这段代码是内存池中,原本的模板变量是T,但是其中又定义了一个U的变量,后来看STL中也都是这么实现的。
原因是这样的:因为内存池分配的时候不仅仅是普通变量,像链表这种还有next指针,所以为了实现这种变量,分配器定义一个other,使用的时候将原本T的普通分配器变换为U的节点分配器,T跟U是有联系的,如下:
template <typename T>
struct StackNode_
{
T data;
StackNode_* prev;
};
/** T is the object to store in the stack, Alloc is the allocator to use */
template <class T, class Alloc = std::allocator<T> >
class StackAlloc
{
public:
typedef StackNode_<T> Node;
typedef typename Alloc::template rebind<Node>::other allocator;
private:
allocator allocator_;
}