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 |capelements 分配的內存的首元素
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;//前面講過
};