GUN C++ STL中的vector的記憶體分配器
GUN C++ STL中的vector的記憶體分配器
//vector 原型 預設情況下其記憶體配置器為std::allocator<_Tp>
template <typename _Tp, typename _Alloc = std::allocator<_Tp>>
class vector : protected _Vector_base<_Tp, _Alloc>;
//_Vector_base原型
template <typename _Tp, typename _Alloc>
struct _Vector_base{
typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template rebind<_Tp>::other _Tp_alloc_type;//stl原始碼剖析上說, 這個其實就是一個allocator<U>, 見alloc_traits
//_Vector_base的一個內部類, 繼承了這個allocator
struct _Vector_impl : _Tp_alloc_type{
pointer _M_start;//目前使用的空間的開始指標
pointer _M_finish;//目前使用的空間的結尾指標
pointer _M_end_of_storage;//目前可用的空間的尾指標
};
};
看一個vector的建構函式
//呼叫形式:vector<string> v(10, "asd");
vector( size_type __n, //建構函式結束時,會析構這個臨時物件allocator
const value_type &__value,
const allocator_type &__a = allocator_type())//此處構造一個臨時的allocator物件
: _Base(__n, __a){//基類複製了這個臨時物件, 生成了自己的內部類
_M_fill_initialize(__n, __value);//這個是負責構造物件的
}
//呼叫基類的這個建構函式
//發現父類中並沒有負責物件的構造,只是負責記憶體的分配
_Vector_base(size_t __n, const allocator_type &__a) : _M_impl(__a){//呼叫_M_impl複製構造
_M_create_storage(__n);//記憶體貌似在這兒分配的
}
//呼叫這個內部類的建構函式
_Vector_impl(_Tp_alloc_type const& __a) _GLIBCXX_NOEXCEPT
: _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0){}
//又呼叫其父類的_Tp_alloc_type複製建構函式,就是std::allocator<_Tp>
//這是一個基類的protected函式
void _M_create_storage(size_t __n){
this->_M_impl._M_start = this->_M_allocate(__n);//分配記憶體
this->_M_impl._M_finish = this->_M_impl._M_start;//裡面還沒有東西
this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
}
//這是一個基類的public函式
pointer _M_allocate(size_t __n){//分配的記憶體大小與呼叫vector時設定的大小一致
//預設情況下_Tp_alloc_type是std::allocator<_Tp>, 見alloc_traits
typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Tr;
return __n != 0 ? _Tr::allocate(_M_impl, __n) : 0;//呼叫該構造器的allocate函式分配記憶體
}
再看_M_fill_initialize
void _M_fill_initialize( size_type __n, const value_type &__value){
std::__uninitialized_fill_n_a(this->_M_impl._M_start,
__n,
__value,
_M_get_Tp_allocator());
this->_M_impl._M_finish = this->_M_impl._M_end_of_storage;
}
//標頭檔案 stl_uninitialized.h中
//此函式還有一個標準模版的版本, 最後一個引數是為了使用預設記憶體分配器std::allocator時使用這個版本
template<typename _ForwardIterator, typename _Size, typename _Tp, typename _Allocator>
void __uninitialized_fill_n_a(_ForwardIterator __first,
_Size __n,
const _Tp& __x,
_Allocator& __alloc);//使用自己的分配器時呼叫此函式
template <typename _ForwardIterator, typename _Size, typename _Tp, typename _Tp2>
inline void __uninitialized_fill_n_a(_ForwardIterator __first,
_Size __n,
const _Tp& __x,
allocator<_Tp2>&){//最後一個引數只是為了函式匹配
std::unitialialized_fill_n(__first, __n, __x);
}
//unitialialized_fill_n
template<typename _ForwardIterator, typename _Size, typename _Tp>
inline void uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x){
//value_type 是迭代器所指向的型別, vector的迭代器其實是一個Random Access Iterator
typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
#if __cplusplus < 201103L
const bool __assignable = true;
#else
// trivial types can have deleted assignment
//利用traits技法"萃取"迭代器所指物件的型別是否支援'複製構造'和'operator='操作
//不過貌似這個一直都是true,即使這兩個函式被宣告為delete
const bool __assignable = is_copy_assignable<_ValueType>::value;
#endif
//__is_trivial 提取迭代器所指物件是否有預設的建構函式
std::__uninitialized_fill_n<__is_trivial(_ValueType) && __assignable>::
__uninit_fill_n(__first, __n, __x);
}
//如果有預設構造
//其中呼叫全域性construct函式, 構造物件
//如果沒有預設夠造函式
//std::__uninitialized_fill_n<true>::__uninit_fill_n函式, 最終呼叫fill_n
vector是如何管理分配的記憶體大小的?
//左值引用版本
//呼叫push_back(_Tp &)時, 會檢查記憶體分配情況, 夠不夠新插入的元素
//_Alloc_traits typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Alloc_traits;
void push_back(const value_type &__x){
if(this->_M_impl._M_finish != this->_M_impl._M_end_of_storage){//檢查是否有空間
_Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish, __x);
++this->_M_impl._M_finish;//有就直接構造物件了
}else//沒有就分配空間再構造
#if __cplusplus >= 201103L
_M_emplace_back_aux(__x);
#else
_M_insert_aux(end(), __x);
#endif
}
//右值引用版本
//_M_emplace_back_aux
//宣告在stl_vector.h中, 定義在vector.tcc檔案中
#if __cplusplus >= 201103L
template<typename _Tp, typename _Alloc>
template<typename... _Args>
void vector<_Tp, _Alloc>::_M_emplace_back_aux(_Args&&... __args){
//從_M_check_len函式可以看出vector的記憶體分配策略
//原大小加上max(size(), 1) __n就是size_type(1)
//const size_type __len = size() + std::max(size(), __n);
const size_type __len = _M_check_len(size_type(1), "vector::_M_emplace_back_aux");
pointer __new_start(this->_M_allocate(__len));//開始分配記憶體
pointer __new_finish(__new_start);//調節尾指標
/*---------------------------------------------------------------------------------*/
__try{//為了在構造了部分物件時,發生了異常,可以析構掉之前已經構造的物件
_Alloc_traits::construct(this->_M_impl, //先構造這個push_back的元素
__new_start + size(), //在start+size()位置構造
std::forward<_Args>(__args)...);//forward保持其左/右值引用屬性
__new_finish = 0;
__new_finish//移動元素,如果可以移動的話 C++primer 第五版 p474
= std::__uninitialized_move_if_noexcept_a
(this->_M_impl._M_start, this->_M_impl._M_finish,
__new_start, _M_get_Tp_allocator());
++__new_finish;
}__catch(...){//如果出現異常
if (!__new_finish)//如果在設定__new_finish = 0之前構造物件就出現異常,析構這一個物件
_Alloc_traits::destroy(this->_M_impl, __new_start + size());
else
std::_Destroy(__new_start, __new_finish, _M_get_Tp_allocator());
_M_deallocate(__new_start, __len);//釋放這塊新記憶體
__throw_exception_again;
}
/*----------------------------------------------------------------------------------*/
std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
_M_get_Tp_allocator());//析構物件
_M_deallocate(this->_M_impl._M_start,
this->_M_impl._M_end_of_storage
- this->_M_impl._M_start);//釋放記憶體
this->_M_impl._M_start = __new_start;
this->_M_impl._M_finish = __new_finish;
this->_M_impl._M_end_of_storage = __new_start + __len;//調節指標
}
#endif
allocator_traits
這個類中有記憶體配置器的大部分介面函式, 只是引數加一個allocator_type, 然後呼叫
//模版定義
template <typename _Alloc>
struct allocator_traits : __allocator_traits_base;
//std::allocator即stl預設的記憶體配置器的特例化版本
template <typename _Tp>
struct allocator_traits<allocator<_Tp>>;
相關文章
- C++ STL -- vectorC++
- 一種高效的 C++ 固定記憶體塊分配器C++記憶體
- STL——STL中vector的實現原理
- C++ vector 釋放記憶體的兩種方法C++記憶體
- go記憶體分配器Go記憶體
- MySQL 配置InnoDB的記憶體分配器MySql記憶體
- 【c++】vector.clear()的記憶體洩露問題C++記憶體洩露
- vector 的記憶體釋放記憶體
- C++ STL學習——vectorC++
- SGI STL 的記憶體管理記憶體
- 核心早期記憶體分配器:memblock記憶體BloC
- 正確釋放Vector的記憶體記憶體
- MySQL記憶體管理,記憶體分配器和作業系統MySql記憶體作業系統
- STL vector中的shrink_to_fit方法(32)
- C++ STL 記憶體配置的設計思想與關鍵原始碼分析C++記憶體原始碼
- C++ STL記憶體配置的設計思想與關鍵原始碼分析C++記憶體原始碼
- vector 避免記憶體頻繁分配釋放與手動釋放vector記憶體記憶體
- 如何設計一個記憶體分配器?記憶體
- C++ 繼承中的記憶體佈局C++繼承記憶體
- 理解 glibc 記憶體分配器的機制與實現記憶體
- c/c++ 標準容器 vector的記憶體空間是如何自動增長的C++記憶體
- C++中“記憶體重疊”C++記憶體
- STL Vector remove()和erase()的使用REM
- Vector() 記憶體釋放 不得不說的故事記憶體
- C++ Vector怎麼樣釋放記憶體,通過swap()函式C++記憶體函式
- 控制C++的記憶體分配C++記憶體
- JS中的棧記憶體、堆記憶體JS記憶體
- C++記憶體管理:簡易記憶體池的實現C++記憶體
- UVA 11991 STL中map、vector的應用
- c++中stack、queue、vector的用法C++
- C++中的動態記憶體與智慧指標C++記憶體指標
- C++基礎::STL中的定理C++
- 《STL原始碼剖析》-- stl_vector.h原始碼
- C++ 物件的記憶體佈局C++物件記憶體
- vector clear() 方法 記憶體釋放問題記憶體
- 使用StringTraits給CString自定義全域性的記憶體分配器AI記憶體
- 初探STL容器之Vector
- STL:vector用法總結