程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++--allocator類的使用

C++--allocator類的使用

編輯:C++入門知識

C++--allocator類的使用


C++為我們提供了安全的內存空間申請方式與釋放方式,但是new與delete表達式卻是把空間的分配回收與對象的構建銷毀緊緊的關聯在一起。實際上,作為與C語言兼容的語言,C++也為我們提供了更加底層的內存操作方式的。

談C++就離不開STL,考慮一下vector<>類的機制,為了高效率的增加與刪除元素,它並不會在我們每次進行添加或刪除操作時進行內存的分配與回收,而是會提前預留下一片空間。我們通過size函數可以得到容器內元素的個數,通過capacity函數則可以得到該容器的實際大小。實際上每個容器都有自己的Allocator類,用於進行空間的分配與回收,對象的構造與銷毀。下面的代碼來自與《C++ primer》,是vector類的push_back函數的一種可能實現方式:

復制代碼
template 
void Vector::push_back(const T& t)
{
// are we out of space?
    if (first_free == end)

        reallocate(); // gets more space and copies existing elements to it

     alloc.construct(first_free, t);

    ++first_free;
}
復制代碼

first_free指向容器中第一個空閒的塊,如果已經沒有空閒塊了,則通過reallocate函數重新分配。alloc是Alloctor類的一個對象,調用其construct方法可在一個指定的區域構建對象,調用的是類型T的拷貝構造函數。在構造完成之後,讓first_free指向下一個空閒塊。

當我們使用new表達式,來調用拷貝構造函數時實際上時伴隨著空間的分配的。那麼Allocator是怎麼做到的呢?實際上它是調用了C++的一個內置的操作符:

void *operator new(size_t); // allocate an object
void *operator new[](size_t); // allocate an array
new (place_address) type
new (place_address) type (initializer-list)

這寫重載操作符函數可以進行內存的分配以及在指定的內存空間進行對象的構造。需要注意的是它們並非new表達式,new表達式是不可以被重載的,實際上new表達式底層也就是調用了這些重載函數的。前兩個用內存的分配,後兩個則用於對象的構造。Alloctor類的construct方法底層實現實際上就是一句調用而已:

new (first_free) T(const T& t);

我們再來看一下reallocate函數的實現:

復制代碼
template  void Vector::reallocate() {
// compute size of current array and allocate space for twice as many elements
    std::ptrdiff_t size = first_free - elements;
    std::ptrdiff_t newcapacity = 2 * max(size, 1);
// allocate space to hold newcapacity number of elements of type T
    T* newelements = alloc.allocate(newcapacity);
// construct copies of the existing elements in the new space
    uninitialized_copy(elements, first_free, newelements);
// destroy the old elements in reverse order
    for (T *p = first_free; p != elements; /* empty */ )
        alloc.destroy(--p);
// deallocate cannot be called on a 0 pointer
    if (elements)
// return the memory that held the elements
        alloc.deallocate(elements, end - elements);
// make our data structure point to the new elements
    elements = newelements;
    first_free = elements + size;
    end = elements + newcapacity;
}
復制代碼

這個實現就稍微復雜一點了,邏輯上我就不說了,著重說明一下其中幾個函數的使用吧。首先是Alloctor類的allocate成員函數的使用,它的作用是向系統申請指定個數的長度為sizeof(T)的連續空間,其底層實現是:

return operator new[](newcapacity * sizeof(T));

uninitialized_copy函數實際上是memory頭文件中的一個函數,它的聲明形式如下:

template 
         ForwardIterator
           uninitialized_copy ( InputIterator first, InputIterator last,
                                ForwardIterator result );

elements指針指向的是vector內部維護的線性表的首地址,該函數的調用實際上將elements與first_free所限定的區域裡的對象拷貝到由newelements 所指向的新分配的的空間中去,其底層也是使用的是拷貝構造函數。

然後是關於Alloctor類的destroy成員函數的分析,它有一個參數,指向需要銷毀的對象的指針,該函數只進行對象的銷毀,但不進行內存的回收。實際上這裡就是簡單的調用析構函數而已(不要質疑,析構函數確實可以通過指針直接調用的哦)。

接下來是關於Alloctor類的deallocate成員函數的分析,它有兩個參數,第一個指向線性表的首地址,第二個參數指明要內存回收的對象的個數,注意,這裡只進行內存回收,而不會進行對象的銷毀,其底層使用的是delete重載函數,同new重載函數一樣,它也不是我們所熟知的delete表達式,而delete表達式其底層則是調用了delete重載函數來釋放內存的,先來看delete有哪些重載函數:

void *operator delete(void*); // free an object
void *operator delete[](void*); // free an array

這兩個版本是分別用來釋放單個對象以及數組對象的。

小結

C++底層為我們提供了內存分配與回收,對象創建與釋放的單獨的手段,它們是operator new, placement new, operator delete以及析構函數(不存在placement delete)。通過這四種手段,我們可以靈活的進行資源的合理管理,但它們是屬於較低層次的手段,STL為我們提供了Allocator類能很好的為我們做這一切,所以,如無必要,我們最好使用Allocator類來進行內存的管理。進行這種級別的內存管理,處理在效率上的提升外,還能有效的減少內存碎片的誕生,這在某些內存資源有限(例如嵌入式設備)的情況下將是一種非常有效的方式。

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