1. 程式人生 > >淺談C++ allocator記憶體管理(對比new的侷限性)

淺談C++ allocator記憶體管理(對比new的侷限性)

STL中,對記憶體管理的alloc的設計,迫使我去學習了allocator類。這裡對allocator記憶體管理做了點筆記留給自己後續查閱。allocator類宣告、定義於標頭檔案<memory>中的std名稱空間內。所以,應該有以下內容位於檔案頭部…

#include <memory>
using namespace std;

文章目錄


1. 我們所知道的malloc和new

再此之前,我只知道兩種開闢記憶體的方式。

其一,可以使用C語言的函式malloc、realloc、calloc開闢記憶體,舉個例子:

int* ptr = (int *)malloc(10 * sizeof(int));	/* 進行強制型別轉換 */

其二,可以使用C++方式開闢記憶體,比如:

int* ptr = new int[10];

對於,C風格的記憶體管理這裡不做討論。但是,對於C++的new風格,這裡總結一下它的侷限性。對於我個人來說,我一般寫成這樣new int[10](),也就是在最後加一對小括號,因為C++保證這樣可以將int[10]

中記憶體全部初始化為0。

2. C++中new的侷限性

對於以上這一段話,有一個話題需要弄清楚的,就是——記憶體構造。

對C++的new而言,它首先會(1)分配記憶體,然後自動的完成(2)物件構造。這裡可以用侯捷先生翻譯的《深度探索C++物件模型》一書中的虛擬碼來表示new的過程:

Point* heap = __new(sizeof(Point));//開闢記憶體
if (head != 0) {
	head->Point::Point();//物件構造(記憶體構造)
}

注意,__new不表示new(它只是完成記憶體申請),以上整個虛擬碼過程為new所完成的功能。
正是因為new的這一連串的操作,造成了效能的下降。比如,

auto p = new string[100];
for (int i = 0; i < 5; ++i){
	p[i] = "balaba...";
}

實際上,我只需要5個string,而new把100個物件全部構造好了(每個string已經被初始化為空字串,也就是"")。

然後,接著又將p[0-4]賦值為balaba…

也就是前面將p[0-4]賦值為空字串的操作,變得毫無意義。

3. 使用allocator將記憶體分配、物件構造分離開

既然,new有它自身的侷限性。對於效能要求極高的STL肯定是不會使用new的。好在有一個allocator類——它也是一個模板類,同時就是用來處理記憶體問題的。

allocator類將new的記憶體分配、物件構造,視作兩個獨立的過程,並由獨立的函式負責。舉個例子:

allocator<char> str;
char* base = str.allocate(10), *p = base; //記憶體分配
str.construct(p++, 'a');  //物件構造並初始化
str.construct(p++, 'b');
cout << base[0] << base[1];

因為allocator是模板類,所以需要指定型別。接著,呼叫allocate(10)函式來分配記憶體(申請了10個char記憶體)。然後,使用construct函式構造base[0]這塊記憶體,並賦以初值a

這就將new記憶體分配、記憶體構造給分離開了。一切,都像我們看到的那樣。

同樣,將delete的過程也拆分了開來。這是必須的,我們不能用delete去釋放allocate分配的記憶體。

str.destroy(--p); //銷燬物件
str.destroy(--p);
str.deallocate(base, 10); //釋放記憶體

小結:如果要使用allocate返回的記憶體,那麼就必須先construct構造它。否則,你後續的行為都是未定義的(造成的後果也是嚴重的)。

但是,有幾個例外。它們是uninitialized_copy、uninitialized_copy_n、uninitialized_fill和uninitialized_fill_n。從名字就知道uninitialized(未初始化的),它們的引數必須指向的是未構造的記憶體,比如uninitialized_copy會在給定位置構造元素。

有興趣可以閱讀《動態記憶體管理allocator類C++ STL標準模板庫vector實現》看看它們的用法。



©為徑
2018-12-23 北京 海淀


Reference:
[1] C++ Primer(第5版)
[2] 深度探索C++物件模型