stl空間配置器
最近在看侯捷的《stl原始碼解析》,按照裡面的思路寫了乙個迷你的stl,由於stl中的記憶體分配和空間配置較為複雜,在這裡總結一下。
c語言中主要有三個函式進行記憶體分配,分別是1.malloc
,realloc
,calloc
,釋放記憶體的函式是free
,標頭檔案是
malloc
函式原型:void *malloc(unsigned int num_bytes);
。分配的是以位元組計算的結果,返回的指標型別是void*
。
注意:不會進行初始化操作,需要手動計算分配的空間大小,同時需要對返回的型別進行強制轉化。
使用:
int * a = (int*)malloc(sizeof(int) * 10);
for (int i = 0; i < 10; ++i)
*(a + i) = i;
for (int i = 0; i < 10; ++i)
cout
<< *(a + i) << " ";
// 0 1 2 3 4 5 6 7 8 9
2.realloc
對原來的位址進行重新分配。如果分配的空間小於原來的空間,還是會在原來的位址上。如果分配的空間大於原來的空間,如果原位址後面空間足夠,則繼續分配;否則會先釋放原來的空間,然後分配新的位址。
函式原型:void *realloc(void *mem_address, unsigned int newsize);
使用:
int *b = (int*)realloc(a, sizeof(int) * 5);
cout
<< (int)b << " "
<< (int)a << endl; // 位址一定相同
int *b = (int*)realloc(a, sizeof(int) * 50);
cout
<< (int)b << " "
<< (int)a << endl; // 位址可能相同
3.calloc
函式原型:void *calloc(size_t n, size_t size);
兩個引數分別是分配的元素個數和單個元素的大小。calloc
的最大特點是會將分配的記憶體初始化為0
使用:
int *c =(int*)calloc(10, sizeof(int));
for (int i = 0; i < 10; ++i)
cout
<< *(c + i) << " ";
// 0 0 0 0 0 0 0 0 0 0
4.free
函式原型:void free(void *ptr)
釋放空間,但需要手動把指標置空,因為只是釋放並沒有改變指標的指向,只是這一塊記憶體已經不屬於這個指標。
c++ 中使用new/delete
來代替c語言中的相關庫函式。主要區別如下:
1.new/delete
是操作符不是庫函式
2.new
會自動計算空間大小
3.new
除了分配空間,還會自動呼叫物件的建構函式,對申請的空間進行構造
4.delete
會先呼叫析構函式,然後釋放空間
正常情況下new/delete
都是完成空間申請,物件構造,物件析構,空間釋放功能,但也有幾個不同的函式原型,提供不同的功能。
1.plain new
這個就是正常的new
,在分配失敗的情況下,丟擲異常std::bad_alloc
而不是返回null
。
void* operator new(std::size_t) throw(std::bad_alloc);
void operator delete(void *) throw();
2.nothrow new
這是不丟擲異常的new
形式,如果分配失敗,返回null
。
void * operator new(std::size_t,const std::nothrow_t&) throw();
void operator delete(void*) throw();
3.placement new
在一塊已經分配空間的記憶體上構造物件,不分配新的空間,不會丟擲異常。
void* operator new(size_t,void*);
void operator delete(void*,void*)
allocate
分配空間
construct
構造
destroy
析構
deallocate
釋放記憶體
memory
的函式將new/delete
的功能拆成四個部分,分別是申請空間,構建,析構,釋放。
具體使用:
allocator alloc;
// 分配
auto begin = alloc.allocate(10);
auto p = begin;
// 構造
for (int i = 0; i < 10; ++i)
alloc.construct(p++, i);
for (int i = 0; i < 10; ++i)
printf("%d ", *(begin + i));
printf("\n");
// 析構
p = begin;
for (int i = 0; i < 10; ++i)
alloc.destroy(p++);
// 釋放記憶體
alloc.deallocate(begin, 10);
在stl的設計中,使用的是多層的空間配置器,因為頻繁的申請釋放空間將會造成記憶體的碎片化。在這裡使用兩層的空間配置器。
一級空間配置器分配的是大於128位元組的空間
如果分配不成功,呼叫控制代碼釋放一部分記憶體
如果還不能分配成功,丟擲異常
維護乙個鍊錶,鍊錶每個節點是8的倍數大小,每乙個子鍊錶擁有相同大小的節點。當使用者申請的空間小於128位元組時,將位元組數擴充套件到8的倍數,然後在自由鍊錶中查詢對應大小的子鍊錶
如果在自由鍊錶查詢不到或者塊數不夠,則向記憶體池進行申請,一般一次申請20塊
如果記憶體池空間足夠,則取出記憶體
如果不夠分配20塊,則分配最多的塊數給自由鍊錶,並且更新每次申請的塊數
如果一塊都無法提供,則把剩餘的記憶體掛到自由鍊錶,然後向系統heap申請空間,如果申請失敗,則看看自由鍊錶還有沒有可用的塊,如果也沒有,則最後呼叫一級空間配置器
在stl的實現中,封裝原始的alloc
,原始的alloc
只分配固定原始的空間,並不會構建和析構物件。封裝後的******allocate
能夠分配空間,構建物件,析構物件,釋放空間。構建物件使用palcement new
,析構物件顯式呼叫析構函式。
具體實現:
template
class ******allocate
static
void deallocate(value_ptr p, size_type n)
static
void construct(value_ptr p, const value_type &value)
static
void destroy(value_ptr p)
};template
allocator******allocate::alloc = allocator();
目前的stl
實現空間配置,set
,vector
,stack
等容器
完整**見github
如有錯誤,歡迎指正~
C C 分配記憶體空間
方法 c malloc calloc realloc free c new delete 函式原型 請求成功返回空間首位址,失敗返回 null include void malloc size t size 分配size位元組的連續記憶體,不負責初始化,使用memset初始化。void calloc...
STL中的記憶體分配方式
在stl中考慮到小型區塊所可能造成的記憶體碎片問題,sgi stl設計了雙層級配置器,第一級配置器直接使用malloc 和free 第二級配置器則視情況採用不同的策略 當配置區塊超過128bytes 時,則視之為足夠大,便呼叫第一級配置器 當配置區塊小於128bytes時,則視之為過小,為了降低額外...
C C 中的記憶體分配機制
本文是總和了其它的幾篇帖子,主要是 一 字串 乙個字元乙個位元組,加上最後的乙個結束符 0 其中,strlen函式返回的字串長度不包括 0 sizeof操作符返回的位元組長度是包括 0 的。二 結構體的儲存 typedef struct sample sizeof sample 為1個位元組 typ...