空間配置器——allocator
主要介紹一下allocator的用法
一、為什麼要有allocator
為什麼會有allocator?原因是new在記憶體分配上面有一些侷限性,new的機制是將記憶體分配和物件構造組合在一起,同樣的,delete也是將物件析構和記憶體釋放組合在一起。但當分配一塊大塊記憶體時,我們想要自己在這塊記憶體上構建物件,將分配空間和構造物件分離,就要用到allocator
C++的STL中定義了很多容器,容器的第二個模板引數通常為allocator型別且有一個預設的allocator。標準庫中allocator類定義在標頭檔案memory中,用於幫助將記憶體分配和物件的構造分離開來。它分配的記憶體是原始的、未構造的。和vector等一樣,allocator也是一個模板類,為了定義一個allocator物件,我們需指明這個allocator可以分配的物件型別,這樣allocator好根據給定的物件型別來確定合適的記憶體空間大小和對齊位置,例:
allocator<string> alloc; //定義了一個可以分配string的allocator物件
auto const p=alloc.allocate(n); //分配n個未初始化的string記憶體,即為n個空string分配了記憶體
二、allocator用法概述
常見操作總結如下:allocator<T> a
- 定義了一個名為a的allocator物件,它可以為型別T的物件分配記憶體
a.allocate(n)
- 分配一段原始的、未構造的記憶體,這段記憶體能儲存n個型別為T的物件
a.deallocate(p,n)
- 釋放T*指標p地址開始的記憶體,這塊記憶體儲存了n個型別為T的物件,p必須是一個先前由allocate返回的指標,且n必須是p建立時所要求的大小,且在呼叫該函式之前必須銷燬在這片記憶體上建立的物件。要求還蠻多的哈,這是因為在建立過程中我們分配的是最原始的記憶體,所以在釋放記憶體時也是隻能嚴格釋放這片最原始的記憶體。
a.construct(p,args)
- p必須是一個型別為T* 的指標,指向一片原始記憶體,arg將被傳遞給型別為T的建構函式,用來在p指向的原始記憶體上構建物件。
a.destory(p)
- p為T*型別的指標,用於對p指向的物件執行解構函式
三、詳情
1.allocate用於分配原始記憶體
construct成員函式接受一個指標和零個或多個額外的引數,在給定位置構造物件,額外的引數是用於初始化構造物件的。
用完物件後,必須對這種構造的的物件呼叫destory銷燬,它接受一個指標,對指向的物件執行解構函式。auto q=p; //q指向最後構造的元素之後的位置 alloc.construct(q++); //*q為空字串 alloc.construct(q++,10,'c'); //*q為cccccccccc alloc.construct(q++,"hi"); //*q為hi
while(q!=p)
alloc.destory(--q);
迴圈開始處,q是指向最後構造的元素之後的一個位置,呼叫destory之前我們先對q進行遞減操作,所以第一次呼叫destory銷燬的是最後一個元素,依次執行銷燬操作直到q和p相等。我們只能對真正構造了的元素進行destory操作。一旦元素被銷燬,就可以重新使用這部分記憶體來儲存其他string或歸還給系統,釋放記憶體通過呼叫deallocate完成。
alloc.deallocate(p,n);
其中p不能為空,必須指向allocate分配的記憶體,而且大小引數n也必須與呼叫allocated分配記憶體時提供的大小引數相等。三、拷貝和填充未初始化記憶體的演算法
allocator還有兩個伴隨演算法,用於在未初始化的記憶體塊中建立物件,這些函式在給定目的位置建立元素,而不是由系統分配記憶體給他們,同樣它們也位於標頭檔案memory中。
uninitialized_copy(b,e,b2)
- 從迭代器b和e指出的輸入範圍中拷貝元素到迭代器b2指定的未構造的原始記憶體中,b2指向的記憶體必須足夠大,能容納輸入序列中元素的拷貝。
uninitialized_copy_n(b,n,b2)
- 從迭代器b指向的元素開始,拷貝n個元素到b2開始的記憶體中
uninitialized_fill(b,e,t)
- 在迭代器b和e指定的原始記憶體範圍中建立物件,物件的值均為t的拷貝
uninitalized_fiil_n(b,n,t)
- 在迭代器b指向的記憶體地址開始建立n個物件,b必須指向足夠大的未構造的原始記憶體,能夠容乃給定數量的物件
以上函式將返回一個迭代器,指向最後一個構造的元素之後的位置。
假定有一個int的vector,希望將它的內容拷貝到動態記憶體中,我們將分配一塊比vector中元素所佔空間大一倍的動態記憶體,然後將原vector中的元素拷貝到前一半空間,後一半用一個給定值進行填充。
//分配比vi向量所佔空間大一倍的動態記憶體
auto p=alloc.allocate(vi.size()*2);
//通過拷貝vi中的元素來構造從p開始的元素
auto q=uninitialized_copy(vi.begin(),vi.end(),p);
//將剩餘元素初始化為42
uninitialized_fill_n(q,vi.size(),42);
來源:C++ primer