注:博客内容均来自于对《STL源码剖析》侯捷,华中科技大学出版社一书的笔记。转载请注明出处。
所有例程在Dev-C++上编译运行,编译选择的是GUN C++11。
1、写在前面
从本篇博客开始,对STL进行更深入的学习。博客内容来源对《STL源码剖析》学习的笔记。其中的个人看法和理解,肯定会存在不妥之处。如果觉得不妥,敬请留言指正。相互交流,探讨,学习才能共同进步。
2、空间配置器
空间配置器在STL中的作用就是在为各个容器分配必要的内存空间。它默默的工作在程序的背后,是各种容器正常工作的必要基础。
3、空间配置器在哪
以STL中的容器vector为例,vector的原型是这样子的:
template <class T, class Alloc = alloc>
class vector
{
//省略
};
在一般使用的时候我们都没有去理会第二个泛型的传入。vector的使用可看前面的博客:
Tips:
在STL的使用中,给出的构造函数都是不带第二个参数的,见下图(来自上面链接的内容)。
从vector的定义原型上可以推测,我们按照要求的空间配置器接口传入一个我们自己设计的空间配置器在理论上也是能行得通的。
4、设计空间配置器
要想设计出一个可以“接入”到程序中的空间配置器,首先要知道空间配置器的必要的接口是什么样子的以及它要提供哪些功能。
4.1 STL中空间配置器的标准接口
STL中空间配置器的标准接口包含必要的数据类型和必要的接口函数。
必要的数据类型:
typedef T value_type;
typedef T* pointer;
typedefconst T* const_pointer;
typedefT& reference;
typedefconst T& const_reference;
typedefsize_t size_type;
typedefptrdiff_t difference_type;
必要的接口函数有:
allocator::rebuild
allocator::allocator 默认构造函数
allocator::allocator(constallocator&) 拷贝构造函数
template<classU> allocator::allocator(const allocator<U>&) 泛型拷贝构造函数
allocator::~allocator() 默认的析构函数
pointerallocator::address() 返回某个对象地址
pointerallocator::address(const_reference x) const 返回某个常量对象的地址
pointer allocator::allocate(size_type n, const void*hint=0) 配置空间
void allocator::deallocate(pointer p, size_type n) 释放配置过的空间
size_typeallocator::max_size() const 返回可配置的最大值
voidallocator::constrct(pointer p, const T& value) 开辟内存
voidallocator::destroy(pointer p) 释放内存
4.2 设计空间配置器
有了上面的基础就可以根据接口来设计一个自己的空间配置器了。
ex2.h
#ifndef __ALLOC_H
#define __ALLOC_H
#include <new> //new
#include <cstddef> //ptrdiff_t, size_t
#include <cstdlib> //exit
#include <climits> //UNIT_MAX
#include <iostream> //cerr
namespace RB
{
using namespace std;
//分配内存
template<class T>
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 memery" << endl;
exit(1);
}
return tmp;
}
//释放内存
template<class T>
inline void _deallocate(T* buffer)
{
::operator delete(buffer);
}
//构造
template<class T1, class T2>
inline void _construct(T1* p, const T2& value)
{
new(p) T1(value);
}
//销毁
template<class T>
inline void _destory(T* ptr)
{
ptr->~T();
}
template<class T>
class alloctor
{
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;
template<class U>
struct rebuild
{
typedef allocator<U> other;
};
//分配内存
pointer 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 constrct(pointer p, const T& value)
{
_construct(p, value);
}
//销毁
void destroy(pointer p)
{
_destroy(p);
}
//返回某个对象的地址,等价:&x
pointer address(reference x)
{
return (pointer)&x;
}
//返回某个const对象的地址,等价:&x
const_pointer const_address(const_reference x)
{
(const_pointer)&x;
}
//返回可成功配置的最大量
size_type max_size() const
{
return size_type(UINT_MAX/sizeof(T));
}
};
}//end of namespace RB
#endif
5、使用自己设计的空间配置器
简单的使用一下我们自己设计的空间配置器。因为空间配置器是工作在背后的,因此使用的时候,我们是不用关注到底用了什么空间。写一个简单的小程序试试:
#include "ex2.h"
#include <vector>
#include <iostream>
#include <iterator>
using namespace std;
int main()
{
vector<int, RB::allocator<int> > iv;
for(int i=0; i<10; ++i)
iv.push_back(i);
copy(iv.begin(), iv.end(), std::ostream_iterator<int>(cout, " "));
cout << endl;
}
运行结果:
从使用和运行上来看,相比使用默认的空间配置器并无很大的差异。着说明我们自己设计的空间配置器确实是运行起来了的。