STL 中对象的构造和析构
在C++中,分配内存的操作一般如下:
class FOO{...};
FOO *fp = new FOO;
.........
delete fp
在new 操作中可以分为两步:
- ::operator new 申请内存
- 在申请的内存上调用FOO的构造函数构造对象
而在delete操作中也可以分为两步:
- 调用FOO的析构函数
- ::operator delete 释放内存
STL 的 allocator 将几个操作都区分开来,内存申请由 alloc::allocatate() 负责,内存释放由alloc::deallocate()负责。对象的构造由::construct()负责,析构由::destory()负责。
STL中负责对象构造和析构的全局函数定义在了 <stl_construct.h> 中,内容不多,才100行左右的代码
construct()
// 开放接口
template <class _T1, class _T2>
inline void construct(_T1* __p, const _T2& __value) {
_Construct(__p, __value);
}
// 开放接口
template <class _T1>
inline void construct(_T1* __p) {
_Construct(__p);
}
template <class _T1, class _T2>
inline void _Construct(_T1* __p, const _T2& __value) {
new ((void*) __p) _T1(__value);
}
template <class _T1>
inline void _Construct(_T1* __p) {
new ((void*) __p) _T1();
}
construct 接口没啥特别的操作,只是将根据传入的参数来选择调用的构造方式。
destory()
template <class _Tp>
inline void destroy(_Tp* __pointer) {
_Destroy(__pointer);
}
template <class _ForwardIterator>
inline void destroy(_ForwardIterator __first, _ForwardIterator __last) {
_Destroy(__first, __last);
}
desotry 则分为两种,一种是传入单个对象的指针,另一种则传入一组迭代器。
template <class _Tp>
inline void destroy(_Tp* __pointer) {
_Destroy(__pointer);
}
template <class _Tp>
inline void _Destroy(_Tp* __pointer) {
__pointer->~_Tp();
}
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*) {}
#ifdef __STL_HAS_WCHAR_T
inline void _Destroy(wchar_t*, wchar_t*) {}
#endif /* __STL_HAS_WCHAR_T */
传入当个指针的版本会根据对象的具体类型来决定是否调用特化版本的析构,不存在特化的则统一调用对象的析构函数。
// 开放接口
template <class _ForwardIterator>
inline void destroy(_ForwardIterator __first, _ForwardIterator __last) {
_Destroy(__first, __last);
}
template <class _ForwardIterator>
inline void _Destroy(_ForwardIterator __first, _ForwardIterator __last) {
// __VALUE_TYPE 取得迭代器所指对象类型
__destroy(__first, __last, __VALUE_TYPE(__first));
}
template <class _ForwardIterator, class _Tp>
inline void
__destroy(_ForwardIterator __first, _ForwardIterator __last, _Tp*)
{
typedef typename __type_traits<_Tp>::has_trivial_destructor
_Trivial_destructor;
// 这边会判断这个对象类型是否是trivial 类型
__destroy_aux(__first, __last, _Trivial_destructor());
}
template <class _ForwardIterator>
void
__destroy_aux(_ForwardIterator __first, _ForwardIterator __last, __false_type)
{
for ( ; __first != __last; ++__first)
destroy(&*__first);
}
template <class _ForwardIterator>
inline void __destroy_aux(_ForwardIterator, _ForwardIterator, __true_type) {}
迭代器版本则会取得迭代器所指的对象类型来判断对象的析构函数是否是traivial 的。 (_Trivial_destructor中是如何做到判断的,书上要在第三章才能知道,这边也还没学习到
小结
STL对于对象的构造和析构调用图如下: