allocator包含于中:
实际实现于三个文件 :
1.stl_construct.h :对象的构造和析构
2.stl_alloc.h空间配置和释放
3.stl_uninitialized.h
1.什么是空间配置器?
为容器取得数据存储空间的类template从用户代码std::vector v;开始,vector的模板参数class T被替换为int,同时第二个模板参数因为没有指定,所以为默认模板参数,即allocator,这个vector对象v会在内部实例一个allocator的对象,用来管理内存。
2.空间配置器需要哪些功能?
负责空间配置与管理,从实现了动态空间配置、空间管理、空间释放的class template
//traits 编程技法可以暂时不了解
allocator::value_type
allocator::pointer
allocator::const_pointer
allocator::reference
allocator::const_reference
allocator::size_type
allocator::difference// 一个嵌套的(nested)class template,class rebind拥有唯一成员other,那是一个typedef,代表allocator
allocator::rebindallocator::allocator() // 默认构造函数
allocator::allocator(const allocator&) // 拷贝构造函数
template allocator::allocator(const allocator&) // 泛化的拷贝构造函数
allocator::~allocator() // 析构函数// 返回某个对象的地址,a.address(x)等同于&x
pointer allocator::address(reference x) const
// 返回某个const对象的地址,a.address(x)等同于&x
const_pointer allocator::address(const_reference x) const// 配置空间,足以存储n个T对象。第二个参数是个提示。实现上可能会利用它来增进区域性(locality),或完全忽略之
pointer allocator::allocate(size_type n, const void* = 0)
// 释放先前配置的空间
void allocator::deallocate(pointer p, size_type n)// 返回可成功配置的最大量
size_type allocator:maxsize() const// 调用对象的构造函数,等同于 new((void*)p) T(x)
void allocator::construct(pointer p, const T& x)
// 调用对象的析构函数,等同于 p->~T()
void allocator::destroy(pointer p)
一个最简单的allocator就可以理解为对new,delete的简单封装,以及对构造函数和析构函数的直接调用。
#ifndef _MYALLOC_
#define _MYALLOC_#include
#include
#include
#include
#include namespace my_alloc
{// allocate的实际实现,简单封装new,当无法获得内存时,报错并退出template inline T* _allocate(ptrdiff_t size, T*) {set_new_handler(0);T* tmp = (T*)(::operator new((size_t)(size * sizeof(T))));if (tmp == 0) {cerr << "out of memory" << endl;exit(1);}return tmp;}// deallocate的实际实现,简单封装deletetemplate inline void _deallocate(T* buffer) { ::operator delete(buffer); }// construct的实际实现,直接调用对象的构造函数template inline void _construct(T1* p, const T2& value) { new(p) T1(value); }// destroy的实际实现,直接调用对象的析构函数template inline void _destroy(T* ptr) { ptr->~T(); }template class allocator {public:typedef T value_type;typedef T* pointer;typedef const T* const_pointer;typedef T& reference;typedef const T& const_reference;typedef size_t size_type;typedef ptrdiff_t difference_type;// 构造函数allocator(){ return; }template allocator(const allocator& c){}// rebind allocator of type Utemplate struct rebind { typedef allocator other; };// allocate,deallocate,construct和destroy函数均调用上面的实际实现// hint used for locality. ref.[Austern],p189pointer allocate(size_type n, const void* hint = 0) {return _allocate((difference_type)n, (pointer)0);}void deallocate(pointer p, size_type n) { _deallocate(p); }void construct(pointer p, const T& value) { _construct(p, value); }void destroy(pointer p) { _destroy(p); }pointer address(reference x) { return (pointer)&x; }const_pointer const_address(const_reference x) { return (const_pointer)&x; }size_type max_size() const { return size_type(UINT_MAX / sizeof(T)); } };
} // end of namespace myalloc
自己编写的allocator为vector分配空间
#include
int main()
{std::vector > v;// Do something;return 0;
}
该实现符合STL标准,但是通过不了GCC编译器,原因是SGI STL的allocator并不完全符合STL规范。在gcc9.2.0(mingw-w64 on msys2)里,上面这个“最简单的allocator实现”微小改动(给set_new_handler、cerr、endl三处加上std::)以后是可以编译通过。
上面实现的满足STL标准的allocator只是简单的实现内存配置/释放,即对new和delete的浅包装,SGI中拥有其独特的操作来优化alloc的性能
1.构造和析构基本工具construct()destory
2.空间的配置与释放工具 一级配置器、二级配置器
3.调用系统内存函数
class Foo{....}
Foo *pf =new Foo;
delete pf
上述代码new操作主要分为两个阶段的操作
1.调用::operator new 配置内存
2.调用构造函数 Foo()构造对象内容
delete也包含两个操作:
1.调用Foo:~Foo()将对象析构
2.调用::operator delete 释放内存
STL 中 内存配置操作由 alloc:allocate 负责
内存释放由alloc::deallocate负责,对象构造由::construct 负责,对象析构由
::destroy负责
直接使用模板编程调用析构函数
template
inline void destroy(T *pointer)
{pointer->~T();
}
template
inline void construct (T1*p,const T2& value)
{new(p) T1(value);
}
在SGI源码中加入了第二版destroy,主要根据trivial来特化实例
在SGI中,alloc优化了申请内存和释放的性能。拿vector来举例,申请一个vector时,我们调用alloc为其申请内存空间。
在SGI中将alloc分为一级适配器和二级适配器,以应用于内存大小不同的场景。大于128bytes直接调用一级alloc,小于则使用二级alloc。二级适配器采用维护16个自由链表来分配内存,这主要是为了解决小型区块可能造成的内存碎片问题。
该函数首先会判断区块大小,大于128bytes调用一级配置器,小于128bytes就找到对应的自由链表,将区块回收
STL 定义了5个全局函数,作用容器配置空间。
1.构造函数 construct
2.析构函数 destroy
3.uninitialized_copy ->copy()
4.uninitialized_fill->fill()
5.uninitialized_fill_n->filln()
本文简单介绍了STL组件之一空间配置器,先从标准接口来简要的理解allocator的功能紧接着用templet编程写了一个简单的allocator,然后记录了SGI 中利用traits编程技法来特化提高函数效率,包括一二级适配器优化内存管理的过程,最后介绍了另外几个内存全局函数。本篇文章并未具体细节代码进行讲解是对《STL源码剖析》框架上的总结,若读者对具体代码有兴趣,可以直接读原书。