Allocator
从实现的角度来看,配置器是一个实现了动态空间配置、空间管理、空间释放的 class template。
defalloc.h
标准的空间分配器。只是实现了基层的分配、释放行为(operator new
和 operator delete
封装),并没有进行优化
allocate/deallocate
基础的分配、释放函数,只是简单的封装了一下operator new
和 operator delete
。
template <class T>
inline T* allocate(ptrdiff_t size, T*) {
set_new_handler(0); // 为了卸载目前的内存分配异常处理函数,强制C++在内存不够的时候抛出std:bad_alloc。
// 申请size个T类型大小的空间
T* tmp = (T*)(::operator new((size_t)(size * sizeof(T))));
if (tmp == 0) {
cerr << "out of memory" << endl;
exit(1);
}
return tmp;
}
template <class T>
inline void deallocate(T* buffer) {
::operator delete(buffer);
}
class allocator
pointer allocate(size_type n) {
return ::allocate((difference_type)n, (pointer)0);
}//分配空间,调用上面封装后的函数
void deallocate(pointer p) { ::deallocate(p); }
pointer address(reference x) { return (pointer)&x; } //获取地址
const_pointer const_address(const_reference x) {
return (const_pointer)&x;
}
size_type init_page_size() {
return max(size_type(1), size_type(4096/sizeof(T)));
}
size_type max_size() const {
return max(size_type(1), size_type(UINT_MAX/sizeof(T)));
}
stl_construct.h
在上述基础上,对对象的构造和析构进行了一定的封装。
construct
构造函数除基本的调用外无重要的点。基本调用的函数为inline void _Construct(_T1* __p, const _T2& __value) { new ((void*) __p) _T1(__value); }
destroy
首先调用萃取机判断是否有析构函数,然后根据反馈分别调用相应的函数。
typedef typename __type_traits<_Tp>::has_trivial_destructor _Trivial_destructor;
// 若是 __true_type,什么都不做;这是 trivial destructor。
template <class _ForwardIterator>
inline void __destroy_aux(_ForwardIterator, _ForwardIterator, __true_type) {}
// 若是 __false_type,这才以循环的方式遍历整个范围,并在循环中每经历一个对象就调用其destory()。(内部调用析构函数)
// 这是 non-trivial destructor
template <class _ForwardIterator>
void __destroy_aux(_ForwardIterator __first, _ForwardIterator __last, __false_type)
{
for ( ; __first != __last; ++__first)
destroy(&*__first);
}
此外,还有一些特化版本(非类,无需过多特殊处理):
inline void _Destroy(char*, char*) {}
inline void _Destroy(int*, int*) {}
inline void _Destroy(long*, long*) {}
inline void _Destroy(float*, float*) {}
inline void _Destroy(double*, double*) {}
stl_uninitialized.h
该部分用于copy、fill大块内存中存储的数据。同样的
uninitialized_copy
该函数实现copy
功能,首先调用萃取机判断是否是POD(传统 旧 数据)数据类型 typedef typename __type_traits<_Tp>::is_POD_type _Is_POD;
,然后根据返回的结果调用不同的函数 return __uninitialized_copy_aux(__first, __last, __result, _Is_POD());
。传统旧数据无需过多操作,直接复制即可。否则,循环调用相应的函数进行构造。
template <class _InputIter, class _ForwardIter>
inline _ForwardIter __uninitialized_copy_aux(_InputIter __first, _InputIter __last,
_ForwardIter __result,
__true_type)
{
return copy(__first, __last, __result);
}
template <class _InputIter, class _ForwardIter>
_ForwardIter __uninitialized_copy_aux(_InputIter __first, _InputIter __last,
_ForwardIter __result,
__false_type)
{
_ForwardIter __cur = __result;
__STL_TRY {
for ( ; __first != __last; ++__first, ++__cur)
_Construct(&*__cur, *__first);
return __cur;
}
__STL_UNWIND(_Destroy(__result, __cur));
}
uninitialized_fill
该函数与上述函数同理,所使用的is_POS_type
及相关处理策略也相同,再此不赘述。
__uninitialized_copy_copy
该函数实现两个范围的拷贝,即为调用两次uninitialized_copy
函数。函数源码如下:
template <class _InputIter1, class _InputIter2, class _ForwardIter>
inline _ForwardIter
__uninitialized_copy_copy(_InputIter1 __first1, _InputIter1 __last1,
_InputIter2 __first2, _InputIter2 __last2,
_ForwardIter __result)
{
_ForwardIter __mid = uninitialized_copy(__first1, __last1, __result);
__STL_TRY {
return uninitialized_copy(__first2, __last2, __mid);
}
__STL_UNWIND(_Destroy(__result, __mid));
}
所实现的功能为拷贝两次。在result
位置,先插入第一个范围,再在新的位置继续插第二个范围。即:
- 首先将 [ f i r s t 1 , l a s t 1 ) \left[first1,last1\right) [first1,last1)数据拷贝到