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++ vector 釋放記憶體的兩種方法C++記憶體
- MySQL 配置InnoDB的記憶體分配器MySql記憶體
- go記憶體分配器Go記憶體
- vector 的記憶體釋放記憶體
- C++ 學習筆記(1):STL、Vector 與 SetC++筆記
- MySQL記憶體管理,記憶體分配器和作業系統MySql記憶體作業系統
- c/c++ 標準容器 vector的記憶體空間是如何自動增長的C++記憶體
- STL容器---Vector
- Vector() 記憶體釋放 不得不說的故事記憶體
- C++記憶體管理:簡易記憶體池的實現C++記憶體
- STL使用篇__vector
- STL---vector(向量)
- JS中的棧記憶體、堆記憶體JS記憶體
- STL:vector用法總結
- 初探STL容器之Vector
- vector clear() 方法 記憶體釋放問題記憶體
- 談談 C++ STL 中的迭代器C++
- C++記憶體管理C++記憶體
- 支援外部記憶體功能的STL容器使用方法分享記憶體
- c++ std::vector 切記C++
- C++的vector容器C++
- STL原始碼剖析——vector容器原始碼
- 最詳細STL(一)vector
- STL----vector注意事項
- STL-Vector容量問題:
- 【C/C++】4.C++的記憶體管理C++記憶體
- go中的記憶體逃逸Go記憶體
- javascript中的記憶體管理JavaScript記憶體
- C++記憶體掃描C++記憶體
- C++記憶體管理剖析C++記憶體
- 什麼是Java記憶體模型(JMM)中的主記憶體和本地記憶體?Java記憶體模型
- C++ 類的記憶體分配是怎麼樣的?C++記憶體
- C++ ——vector陣列筆記C++陣列筆記
- C++中vector<int>& numsC++
- C++ 容器vector的使用C++
- C++STL第二篇(vector的原理用法)C++
- 跟我學C++中級篇——STL的學習C++
- 請描述C/C++程式的記憶體分割槽?C++記憶體