引言
前文 提到allocator类将new操作符内存的分配与对象的构造或delete操作符对象的析构和内存的释放分为两个阶段。内存的分配拟和释放分别由::allocate()和::deallocate()负责;对象的构造和析构分别由 ::construct()和::destroy()负责。本文参考《STL源码剖析》和SGI STL实现,分析allocator类中的构造与析构。
destroy函数和construct函数的实现
construct函数很简单,只是利用placement new调用对象的构造函数。而destory函数就稍微复杂一些,利用了type_traits编程技巧,判断迭代器所指元素类型中是否有non-trivial 析构函数,如果没有则直接结束,否则依次调用析构函数。这样处理的话,万一需要对很大范围的对象执行析构函数,但是析构函数都是无关痛痒的(trivial)则没有必要一次次调用析构函数,这样能大大提高效率。
#include<new>
#include<iostream>
#include<type_traits>
template<class T1,class T2>
inline void construct(T1 *p, const T2& value){
new (p)T1(value); //placement new;call T1::T1(value);
}
//destroy第一个版本,接受一个指针
template<class T>
inline void destroy(T* pointer){
pointer->~T();
}
//第二个版本接受两个迭代器,释放一个范围的内存,利用type_traits<>根据不同类型求得最适当的措施
template<class ForwardIterator>
inline void destroy(ForwardIterator first, ForwardIterator last){
__destroy(first, last, std::_Val_type(first));
}
template<class ForwardIterator,class T>
inline void __destroy(ForwardIterator first, ForwardIterator last, T*){
__destroy_aux(first, last, std::has_trivial_destructor<T>());
}
template<class ForwardIterator>
inline void __destroy_aux(ForwardIterator first, ForwardIterator last, std::false_type){
std::cout << "in false_type" << std::endl;
for (; first < last; ++first)
destroy(&(*first));
}
template<class ForwardIterator>
inline void __destroy_aux(ForwardIterator first, ForwardIterator last, std::true_type){
std::cout << "in true_type" << std::endl;
}
SGI STL的实现
SGI STL是STL的经典实现之一,那么SGI是如何考虑allocator的设计呢?
1. 从heap申请空间
2. 考虑多线程
3. 考虑内存不足
4. 考虑内存碎片
为了简化问题,我们不考虑多线程的情况。
剩下的三个问题中,申请内存可以采用malloc和free库函数,内存不足也在其中相应的考虑。而内存碎片则需要更精细的考虑。
内存碎片
当程序同时处理一系列内存需求