allocator類
C++中,內存分配和對象構造緊密糾纏(new),就像對象析構和回收一樣(delete)。如果程序員想接管內存分配,即將內存分配和對象構造分開,對於前者,主要是分配和釋放未構造的原始內存;對於后者,主要是在原始內存中構造和撤銷對象。
分配和釋放未構造的原始內存 兩種方法:
- allocator類,提供可感知類型的內存分配;
- 標准庫中的opeator new和operator delete,它們分配和釋放需要大小的原始、未類型化的內存;
在原始內存中構造和撤銷對象 不同方法:
- allocator類定義了名為construct和destroy的成員;
- placement new表達式,接受指向未構造內存的指針;
- 直接調用對象的析構函數來撤銷對象;
- 算法uninitialized_fill 和 uninitialized_copy,在目的地構造對象;
C++的STL中定義了很多容器,容器的第二個模板參數通常為allocator類型,標准庫中allocator類定義在頭文件memory中,用於幫助將內存分配和對象的構造分離開來。它分配的內存是原始的、未構造的。
表達式 | 說明 |
allocator<T> a | 定義了一個名為a的allocator對象,它可以為類型T的對象分配內存 |
a.allocator(n) | 分配一段原始的、未構造的內存,這段內存能保存n個類型為T的對象 |
a.deallocate(p, n) | 釋放T*指針p地址開始的內存,這塊內存保存了n個類型為T的對象,p必須是一個先前由allocate返回的指針, 且n必須是p創建時所要求的大小,且在調用該函數之前必須銷毀在這片內存上創建的對象。 |
a.construct(p, t) | 在T*指針p所指向內存中構造一個新元素。運行T類型的復制構造函數用t初始化該對象 |
a.destory(p) | 運行T*指針p所指向對象的析構函數 |
uninitialized_copy(b,e,b2) | 從迭代器b和e指出的輸入范圍中拷貝元素到從迭代器b2開始的未構造的原始內存中,該函數在目的地構造元素,而不是給它們復制。 假定由b2指出的目的地足以保存輸入范圍中元素的副本 |
uninitialized_fill(b,e,t) | 將由迭代器b和e指出的范圍中的對象初始化為t的副本,假定該范圍是未構造的原始內存,使用復制構造函數構造對象 |
uninitalized_fiil_n(b,e,t,n) | 將由迭代器b和e指出的范圍中至多n個對象初始化為t的副本,假定范圍至少為n個元素大小,使用復制構造函數構造對象 |
STL都會使用allocator類來為容器分配空間,例如:
#include <memory> template <class T> class Vector { public: Vector(): elements(0), first_free(0), end(0) {} void push_back(const T&); private: static std::allocator<T> alloc; // object to get raw memory void reallocate(); // get more space and copy existing elements T* elements; // pointer to first elment in the array T* first_free; // pointer to first free element in the array T* end; // pointer to one past the end of the array }; template <class T> std::allocator<T> Vector<T>::alloc; template <class T> void Vector<T>::push_back(const T& t) { if (first_free == end) { reallocate(); } alloc.construct(first_free, t); first_free++; } template <class T> void Vector<T>::reallocate() { // compute size of current array and allocate space for twice as many elements std::ptrdiff_t size = first_free - elements; std::ptrdiff_t newcapacity = 2 * (size > 1 ? size : 1); T* newelements = alloc.allocate(newcapacity); std::uninitialized_copy(elements, first_free, newelements); for (T* p = first_free; p != elements; alloc.destroy(--p)); if (elements) { alloc.deallocate(elements, end - elements); } elements = newelements; first_free = elements + size; end = elements + newcapacity; }