古詩詞大全網 - 成語經典 - C++類內使用allocator的問題

C++類內使用allocator的問題

allocator<T> a a可以為類型為T的對象分配內存

a.allocate(n) 分配壹段原始的未構造的內存,可以保存n個T類型的對象

a.deallocate(p,n) 釋放T*指針p中地址開始的內存,保存了n個類型為T的對象;p必須是allocate返回的指針,n必須是p創建時所要求的大小,必須保證這些指針調用過destroy

a.construct(p, args) p必須是T*指針,指向原始內存,args傳遞給構造函數

a.destroy(p) p位T*指針,對p執行析構函數(銷毀)

使用須知:

不要使用未構造的內存,小心越界,釋放之前壹定要銷毀,只能銷毀真正構造了得元素

p(內存未構造)---->p(可以使用)--------->p(使用結束)------------>p(釋放內存)

a.allocate(p) ?a.construct(p) ?a.destroy(p) a.deallocate(p)

指針不能為空

例子:

動態內存管理類StrVec模仿std::vector<std::string>

使用allocator分配內存

指針成員

[0] [1] [2] [3] [4] [5]-----------未構造元素------------

^ ?^ ?^

|elements |first_free |cap

elements 分配的內存的首元素

first_free ?實際元素之後的位置(已構造元素的尾後元素,未構造元素的首元素)

cap ? 分配內存末尾之後的位置

allocator<string>內存分配器

方法:

alloc_n_copy 分配內存,拷貝元素

free 銷毀元素,釋放內存

chk_n_alloc 檢查空間,不夠則分配新內存

reallocate 分配心內存

定義:

class?StrVec

{

public:

StrVec():?//默認初始化

elements(nullptr),?first_free(nullptr),?cap(nullptr){}

StrVec(const?StrVec?&s)//拷貝構造函數

{

//分配內存,大小與s壹樣

auto?newdata?=?alloc_n_copy(s.begin(),?s.end());

elements?=?newdata.first;

first_free?=?cap?=?newdata.second;

}

StrVec?&operator=(const?StrVec?&rhs)//拷貝賦值

{

//分配內存,大小與rhs壹樣

auto?data?=?alloc_n_copy(rhs.begin(),?rhs.end());

free();

elements?=?data.first;

first_free?=?cap?=?data.second;

return?*this;

}

~StrVec()//析構

{free();}

void?push_back(const?std::string&)//拷貝元素(別告訴我妳沒見過這個名字)

{

chk_n_alloc();?//檢查空間

alloc.construct(first_free++,?s);?//構造s的副本(註意後置遞增)

}

size_t?size()?const?{return?first_free?-?elements;}

size_t?capacity()?const?{return?cap?-?elements;}?//這些都是vector的名字,壹個效果

std::string?*begin()?const{return?elements;}

std::string?*end()?const{return?first_free;}//前面解釋過了

private:

Static?std::allocator<std::string>?alloc;//分配元素

void?chk_n_alloc()

{

if(size()?==?capacity())?//分配的內存用完

reallocate();?//重新分配

}

std::pair<std::string*,?std::string*>?alloc_n_copy(const?std::string*,?const?std::string*)

{

//分配空間

auto?data?=?alloc.allocate(e?-?b);

return?{data,?uninitialized_copy(b,?e,?data)};

}

void?free()?//銷毀元素釋放內存

{

//不能傳遞給deallocate壹個空指針,如果為零,函數不作為

if(elements)

{

//逆序銷毀舊元素(析構)

for?(auto?p?=?first_free;?p?!=?elements;/*空下*/)

alloc.destory(--p);//這裏先遞減,遞減後的指針銷毀

//這裏釋放內存空間

alloc.deallocate(elements,?cap?-?elements);

}

}

void?reallocate()//重新分配內存

{

//分配兩倍的空間

auto?newcapacity?=?size()2?*?size()?:?1;

//1的作用是因為0?*?2?=?0,使空元素分配壹個空間

auto?newdata?=?alloc.allocate(newcapacity);

//將數據從舊內存移動到新內存

auto?dest?=?newdata;

auto?elem?=?elements;

for(size_t?i?=?0;i?!=?size();?++i)

alloc.construct(dest++,?std::move(*elem++));

free();

//更新數據結構

elements?=?newdata;

first_free?=?dest;

cap?=?elements?+?newcapacity;

}

std::string?*elements;

std::string?*first_free;

std::string?*cap;//前面講過

};