程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 第18章 特殊工具與技術(1)

第18章 特殊工具與技術(1)

編輯:C++入門知識

18.1 優化內存分配

C++的內存分配是一種類型化操作:new為特定類型分配內存,並在新分配的內存中構造該類型的一個對象。new表達式自動運行合適的構造函數來初始化每個動態分配的類類型。

18.1.1 C++中的內存分配

C++中,內存分配和對象構造緊密糾纏,就像析構和內存回收一樣。使用new表達式的時候,分配內存,並在該內存中構造一個對象;使用delete表達式時,調用析構函數撤銷對象,並將對象所用內存返還給系統。

接管內存分配時,必須處理兩個任務。分配原始內存時,必須在該內存中構造對象;在釋放該內存之前,必須保證適當地撤銷這些對象。

對未構造的內存中的對象進行賦值而不是初始化,其行為是未定義的。對許多類而言,這樣做引起運行時崩潰。賦值涉及刪除現存對象,如果沒有現存對象,賦值操作符中的動作就會有災難性效果。

C++提供下面兩種方法分配和釋放未構造的原始內存:

(1) allocater類,它提供可感知類型的內存分配。這個類支持一個抽象接口,以分配內存並隨後使用該內存保護對象。

(2)標准庫中的operator new和operator delete,它們分配和釋放需要大小的原始的、未類型化的內存。

C++還提供不同的方法在原始內存中構造和撤銷對象。

(1)allocator類定義了名為construct和destroy的成員,其操作正如它們的名字所指出的那樣:construct成員在未構造內存中初始化對象,destroy成員在對象上運行適當的析構函數。

(2)定位new表達式(placement new expression)接受指向未構造內存的指針,並在該空間中初始化一個對象或一個數組。

(3)可以直接調用對象的析構函數來撤銷對象。運行析構函數並不釋放對象所在的內存。

(4)算法uninittialized_fill和uninitialized_copy像fill和copy算法一樣執行,除了它們在目的地構造對象而不是給對象賦值之外。

現代C++程序一般應該使用allocator類來分配內存,它更安全靈活。但是,在構造對象的時候,用new表達式比allocator::construct成員更靈活。有幾種情況下必須用new。

18.1.2 allocator類

allocator類是一個模板,它提供類型化的內存分配以及對象構造和撤銷。

allocator類將內存分配和對象構造分開。當allocator對象分配內存的時候,它分配適當大小並排列成保存給定類型的對象的空間。但是,它分配的內存是未構造的,allocator的用戶必須分別construct和destroy放置在該內存中的對象。

1. 使用allocator管理類成員數據

vector所用存儲開始是未構造內存,它還沒有保存任何對象。將元素賦值或增加到這個預分配空間的時候,必須使用allocator類的construct成員構造元素。


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; 
    void reallocate(); 
    T* elements; //first element  
    T* first_free; //behind the last actual element  
    T* end; //behind vector conent  
}; 
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;
 void reallocate();
 T* elements; //first element
 T* first_free; //behind the last actual element
 T* end; //behind vector conent
};
2. 使用construct


template<class T> 
void Vector<T>::push_back(const T& t){ 
if(first_free==end) 
    reallocate(); //gets more space and copies existing elements to it  
alloc.construct(first_free,t); 
++first_free; 

template<class T>
void Vector<T>::push_back(const T& t){
if(first_free==end)
 reallocate(); //gets more space and copies existing elements to it
alloc.construct(first_free,t);
++first_free;
}3. 重新分配元素與復制元素


template <class T> 
void Vector<T>::reallocate(){ 
std::ptrdiff_t size=first_free-elements; 
std::ptrdiff_t newcapacity=2*max(size,1); 
T* newelements=alloc.allocate(newcapacity); 
 
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; 

template <class T>
void Vector<T>::reallocate(){
std::ptrdiff_t size=first_free-elements;
std::ptrdiff_t newcapacity=2*max(size,1);
T* newelements=alloc.allocate(newcapacity);

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;
}
每次重新分配時分配兩倍內存。

deallocate期待指向由allocate分配的空間的指針,傳給deallocate一個零指針是不合法的。

 摘自 xufei96的專欄
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved