首先需要了解内存分配的一个过程:程序调用=》allocator=》new=》malloc=》操作系统分配。
然后要理解三个有关于new的概念
- new operator:分配内存并初始化对象,不可被重载
- operator new:只分配内存,不初始化对象,可被重载,相当于C的malloc
- placement new:对分配好的内存进行初始化
Foo * p = new (ptr) Foo(value); // ptr指向已经分配内存的起始位置
SGI配置器
SGI STL的配置器与标准规范不同,其名称为alloc而非allocator,不接受任何参数。所以在VC或CB需要这么指定配置器:
vector<int,std::allocator<int>> iv;
而在GCC中,需这样指定:
vector<int,std::alloc<int>> iv;
但其实SGI STL也支持allocator,只是效率不佳,仅仅对::operator new做了一层薄薄的封装。
一般来说,以下代码分为两阶段:(1)调用::operator new配置内存;(2)调用Foo::Foo()构造对象内容。
Foo* pf=new Foo;
STL alloc将这两阶段分开,内存配置交给alloc::allocate()负责,对象构造交给::construct()负责。
配置器定义于< memory>中,SGI <memory>内含两个文件
<stl_alloc.h>:负责内存空间的配置和释放
<stl_construct.h>:负责对象内容的构造和析构
还有个重要的文件 <stl_uninitialized.h>:用来fill或copy大块内存数据
stl_construct.h
定义了全局函数construct() 和 destroy()
construct() 核心代码
// 将初值 __value 设定到指针所指的空间上。
template <class _T1, class _T2>
inline void _Construct(_T1* __p, const _T2& __value) {
new ((void*) __p) _T1(__value); // placement new,调用 _T1::_T1(__value);
}
destroy()核心代码
// 第一个版本,接受一个指针,准备将该指针所指之物析构掉。
template <class _Tp>
inline void _Destroy(_Tp* __pointer) {
__pointer->~_Tp();
}
// 第二个版本,接收两个迭代器。
// 调用 __VALUE_TYPE() 获得迭代器所指对象的类别
template <class _ForwardIterator>
inline void _Destroy(_ForwardIterator __first, _ForwardIterator __last) {
__destroy(__first, __last, __VALUE_TYPE(__first));
}
其实destroy还有一个需要判断的地方:
判断value_type时,如果这些元素有自己的析构函数,则这个析构函数叫做non-trivial destructor(构造函数、析构函数、拷贝构造函数、复制构造函数都可能是non-trivial)。
POD类型是C++的内建类型或传统C结构体类型,必有trivial ctor/dtor/copy/assignment四种函数。
若value_type没有non-trivail destructor,则说明这个对象的析构是无意义的,因而不需要一次又一次地调用那些无关痛痒的析构函数,直接调用malloc()、memcpy()等内存操作提高性能。
判断value_type是否有non-trival destrory的方法:
// 利用__type_traits<T>判断一个对象的所述类,进而得知该类型的析构函数是否需要做什么。
// 如果为true,则什么也不用做;否则,逐个调用第一个版本的析构函数
template <class _ForwardIterator, class _Tp>
inline void
__destroy(_ForwardIterator __first, _ForwardIterator __last, _Tp*)
{
typedef typename __type_traits<_Tp>::has_trivial_destructor
_Trivial_destructor;
__destroy_aux(__first, __last, _Trivial_destructor());
}
内存分配方面的内容(<stl_alloc.h>, <stl_uninitialized.h>),由于篇幅限制,放到下一篇讲了。