空间配置器为
STL
容器分配
存储数据的空间,空间不一定是内存,也可以是磁盘或其它辅助存储介质。
一般而言,我们所习惯的C++
内存配置操作和释放操作是这样的:
class Foo { ... };
Foo *pf = new Foo;
delete pf;
这其中的new
包含两步操作:
(1)
调用::operator new
配置内存;
(2)
调用Foo::Foo()
构造对象。
delete
也包含两步操作:
(1)
调用Foo::~Foo()
将对象析构;
(2)
调用::operator delete
释放内存。
详情见C++关键字new和delete
为了精密分工,STL allocator
将这两步区分开来。
alloc::allocate()
负责配置内存;
alloc::deallocate()
负责释放内存;
::construct()
负责构造对象;
::destroy()
负责析构对象。
构造对象
template <typename T1, typename T2>
inline void construct(T1 *p, const T2 &value)
{
new (p) T1(value);
}
construct
接受一个指针p
和一个初值value
,该函数的用途就是将value
设定到指针所指的空间上。C++
的placement new
运算可完成这一任务。
p
所指向的内存一定得是预先分配好的。construct
只负责向该内存中写数据。
析构对象
版本1
template <typename T>
inline void destroy(T *pointer)
{
pointer->~T();
}
destroy
函数接受一个指针,将该指针所指的对象析构掉(调用析构函数)。
版本2
destroy
的另一种重载实现如下。接受first
和last
两个迭代器,准备将[first, last)
范围内的所有对象都析构掉。我们不知道这个范围有多大,万一很大,而且每个对象的析构函数都无关痛痒(即所谓的trivial destructor
),那么一次次地调用这些析构函数只会白白地浪费CPU
资源。
template <typename ForwardIterator>
inline void destroy(ForwardIterator first, ForwardIterator last)
{
__destroy(first, last, value_type(first));
}
个人理解:所谓
trivial destructor
,即析构函数里没有任何自定义的行为(如将new的堆内存delete掉)。
因此,使用value_type()
获得迭代器所指对象的型别,再利用__type_traits<T>
判断该型别的析构函数是否是trivial
的。
template <typename ForwardIterator, typename T>
inline void __destroy(ForwardIterator first, ForwardIterator last, T*)
{
typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;
__destroy_aux(first, last, trivial_destructor());
}
若是,就什么也不用做。
template <typename ForwardIterator, typename T>
inline void __destroy_aux(ForwardIterator first, ForwardIterator last, __true_type) {}
不调用
trivial destructor
否则循环遍历整个范围,每遍历到一个对象就调用一次destroy()
template <typename ForwardIterator, typename T>
inline void __destroy_aux(ForwardIterator first, ForwardIterator last, __false_type)
{
while (first != last) {
destroy(first.get());
++first;
}
}
需要调用析构函数
那如何判断迭代器所指对象的型别(value_type()
)以及析构函数是否是trivial的(__type_traits<>
)?
讲迭代器的时候再说。。。