allocator类初学的简单例子
?
? ? ? ? 在C++中,我們基本用new(delete)操作符分配(釋放)內(nèi)存。new操作符為特定類型分配內(nèi)存,并在新分配的內(nèi)存中構(gòu)造該類型的一個(gè)對(duì)象。new表達(dá)式自動(dòng)運(yùn)行合適的構(gòu)造函數(shù)來初始化每個(gè)動(dòng)態(tài)分配的類類型對(duì)象。即new表達(dá)式既分配了內(nèi)存同時(shí)也構(gòu)造了對(duì)象。
然而,我們一定會(huì)遇到這樣的情況:預(yù)先分配用于創(chuàng)建新對(duì)象的內(nèi)存,需要時(shí)在預(yù)先分配的內(nèi)存中構(gòu)造每個(gè)對(duì)象。即將內(nèi)存分配與對(duì)象構(gòu)造分開進(jìn)行,這樣做的理由是:
(1)在內(nèi)存分配時(shí)構(gòu)造對(duì)象很浪費(fèi),可能會(huì)創(chuàng)建從不使用的對(duì)象。
(2)當(dāng)實(shí)際使用預(yù)先分配的對(duì)象時(shí),被使用的對(duì)象很可能要重賦新值。
string* pstr = new string[5];上面舉了個(gè)不合適的例子(當(dāng)然你應(yīng)該用vector<string>來代替),毫無疑問被分配的5個(gè)string空間是被string默認(rèn)構(gòu)造函數(shù)初始化了,而且接下來你肯定得對(duì)pstr[0...4]重新賦值。所以new操作符這種分配特點(diǎn)會(huì)增加運(yùn)行時(shí)開銷。尤其是某些用戶的類類型要求對(duì)象分配更快一些,做法通常是:預(yù)先分配用于創(chuàng)建新對(duì)象的內(nèi)存,需要時(shí)在預(yù)先分配的內(nèi)存中構(gòu)造每個(gè)新對(duì)象。
#include <iostream> #include <string>? #include <memory> using namespace std; int main() { int n = 10; string *const p = new string[n]; string s; string *q = p;while(cin >> s && q != p + n){*q ++ = s;?? ?}?? ?const size_t len ?= q - p;cout << "There is: " << len << " elements." << endl;cout << "Hello World";delete[]p;return 0; }new有如下的特點(diǎn):
(1)它將內(nèi)存分配和對(duì)象的構(gòu)造組合在了一起。相應(yīng)地,delete將對(duì)象的析構(gòu)和內(nèi)存的釋放放在了一起。
(2)如上例子,new表達(dá)式分配了并初始化了n個(gè)string,但是我們可能不需要n個(gè)string,少量的string可能就足夠了。這樣我們就可能創(chuàng)建了一些永遠(yuǎn)也用不到的對(duì)象。而且,對(duì)于那些卻是需要使用的對(duì)象,我們也在初始化之后賦予了它們新值。每個(gè)使用到的對(duì)象都被賦值了2次:第一次在默認(rèn)初始化時(shí),第二次在賦值時(shí)。
(3)對(duì)于一個(gè)沒有默認(rèn)構(gòu)造函數(shù)的類,那么不能定義動(dòng)態(tài)分配數(shù)組了。
但是,當(dāng)我們分配一大塊內(nèi)存的時(shí)候,我們一般把內(nèi)存分配和對(duì)象的構(gòu)造分離。這意味著我們可以分配大塊內(nèi)存,但是只在需要時(shí)候才真正執(zhí)行對(duì)象的構(gòu)建操作(同時(shí)付出一定的開銷)。
? ? ?allocator類將內(nèi)存分配和對(duì)象構(gòu)造分開。當(dāng)allocator對(duì)象分配內(nèi)存的時(shí),它分配適當(dāng)大小并排列成保存給定類型對(duì)象的空間。它分配的內(nèi)存是未被構(gòu)造的,allocator的用戶必須分別construct和destroy放置在該內(nèi)存中的對(duì)象。
vector的自增長告訴我們:vector為了實(shí)現(xiàn)快速內(nèi)存分配,其實(shí)際分配的空間要比當(dāng)前需要的空間多一些。(實(shí)際空間因庫的實(shí)現(xiàn)不同而不同),下面為了說明allocator的使用,我們簡(jiǎn)陋地實(shí)現(xiàn)STL vector中的push_back操作。
template <class T> class VECTOR { public:VECTOR() : elements(NULL), first_free(NULL), end(NULL){}void push_back(const T&); private:static allocator<T> alloc;void reallocate();T *elements;T *first_free;T *end; };elements:指向數(shù)組的第一個(gè)元素;first_free:指向最后一個(gè)實(shí)際元素之后的那個(gè)元素;end:指向數(shù)組本身之后的那個(gè)元素??聪旅孢@張圖可能更清楚一點(diǎn)。
?
template <class T> void VECTOR<T>::push_back(const T& t) {if (first_free == end) //確認(rèn)是否有可用空間{reallocate(); //分配新空間并復(fù)制現(xiàn)存元素}alloc.construct(first_free, t); //構(gòu)造新元素++first_free; }?
下面是reallocate()的簡(jiǎn)單實(shí)現(xiàn):
?
template <class T> void VECTOR<T>::reallocate() {ptrdiff_t size = first_free - elements;ptrdiff_t newCapacity = 2 * max(size, 1);T *newElement = alloc.allocate(newCapacity); //分配兩倍內(nèi)存uninitialized_copy(elements, first_free, newElement); //原內(nèi)存元素拷貝到新內(nèi)存for (T *p = first_free; p != elements; ) //原內(nèi)存元素逆序調(diào)用析構(gòu)函數(shù){alloc.destroy(--p);}if (elements){alloc.deallocate(elements, end - elements); //撤銷原內(nèi)存空間}elements = newElement; //調(diào)整新內(nèi)存空間指針指向first_free = elements + size;end = elements + newCapacity; }說明:本例只做簡(jiǎn)單說明。如果你對(duì)vector或STL實(shí)現(xiàn)感興趣,可以拜讀《STL源碼分析》這本書,我也從這本書學(xué)到很多知識(shí)。
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
總結(jié)
以上是生活随笔為你收集整理的allocator类初学的简单例子的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++位运算符
- 下一篇: access学习网站