天天看點

STL源碼剖析學習筆記之具備次配置力(sub-allocation)的SGI空間配置器

SGI特殊的空間配置器: std::alloc

一般而言,我們所習慣的的C++記憶體配置操作和釋放操作是這樣的:

class Foo {…};

Foo* pf=new Foo;//配置記憶體,然後構造對象

delete pf; //将對象析構,然後釋放記憶體

其中new算式内含兩階段操作:

1.調用 ::operator new 配置記憶體;

template <class T>
inline T* allocate(ptrdiff_t size,T*){
    set_new_handler();//set_new_handler的傳回值是一個函數指針,該函數指針指向調用  set_new_handler之前的異常處理函數,參數設定為0,表示空的。如果參數不為0,則會抛出異常

    T* tmp=(T*)(::operator new((size_t)size*sizeof(T))));
    if(tmp==){
       cerr<<"out of memory"<<endl;
       exit();
  }
  return tmp;
}
           

2.調用 Foo::Foo()構造對象内容

#include<new.h>//欲使用placement new 需要包含此檔案

template<class T1,class T2>
inline void construct(T1* p , const T2& value){
    new (p) T1(value);//将初值設定到指針所指的空間上
}
           

其中delete算式内含兩階段操作:

1.調用 Foo::~Foo()将對象析構;

//以下是destroy()第一版本,接受一個指針
template <class T>
inline void destroy(T* pointer){
     pointer->~T();将該指針所指之物析構掉
}

//以下是destroy()第二版本,接受兩個疊代器,此函數設法找出元素的數值型别
//進而利用_type_traits<>求取最适當措施
template <class ForwardIterator>
inline void destroy(ForwardIterator first,ForwardIterator last){
     _destroy(first,last,value_type(first));
}

//判斷元素的數值型别(value type)是否有trivial destructor
template <class ForwardIterator,class T>
inline void_destroy(ForwardIterator first,ForwarIterrator last,T*){
     typedef typename _type_traits<T>::has_trivial_destructor    trivial_destructor;
     _destroy_aux(first,last,trivial_destructor());
}

//如果元素的數值型别(value_type)有non-trivial destructor
template <class ForwardIterator>
inline void _destroy_aux(ForwardIterator first,ForwardIterator last,_false_type){
     for( ;first<last;++first)
     {
        destroy(&*first);
     }
}

//如果元素的數值型别(value_type)有trivial destructor
template <class ForwardIterator>
inline void_destroy_aux(ForwardIterator,ForwardIterator,_true_type){}
           

destroy()有兩個版本,第一個版本接受一個指針,準備将該指針所指之物析構掉,直接調用該對象的析構函數即可。第二個版本接受first和last兩個疊代器,準備将(first,last)範圍内所有對象析構掉,我們不知道這個範圍多大,萬一很大,而每個對象的析構函數都無關痛癢(即trivial destructor),那麼一次次調用這些無關痛癢的析構函數,對效率是一種傷害。是以,這裡首先利用value_type()獲得疊代器所指對象的型别,再利用_type_traits來判斷型别的析構函數是否無關痛癢。若是(true_type),則什麼也不做就結束;若不是無關痛癢的(_false_type),這才以循環方式巡訪整個範圍,并在循環中每經曆一個對象就調用第一個版本的destroy()。

2.調用 ::operator delete釋放記憶體;

template <class T>
inline void deallocate(T* buffer){
    ::operator delete(buffer);
}
           

為了精密分工,STL allocator決定就将這兩階段操作區分開來

1.記憶體配置操作由alloc::allocate()負責,記憶體釋放由alloc::deallocate()負責

2.對象構造操作由 ::construct()負責,對象析構操作由 ::destroy()操作

STL标準規格告訴我們,配置器定義于之中,SGI 内含一下兩個檔案:

#include<stl_alloc.h>     //負責記憶體空間的配置與釋放
#include<stl_construct.h> //負責對象内容的構造與析構
           

繼續閱讀