- new與placement new
-
new:
- 先調用operator new(大小),而operator new()會調用malloc嘗試分配內存,失敗則調用_callnewh()來釋放內存,直至分配成功
- 可以設置分配失敗的處理函數:將寫好的處理函數作為參數傳入set_new_handler即可
- 然后將得到的指針轉型
- 最后通過指針調用構造函數
- 先調用operator new(大小),而operator new()會調用malloc嘗試分配內存,失敗則調用_callnewh()來釋放內存,直至分配成功
-
placement new
- 先調用operator new(大小, address),該帶2個參數的函數直接返回buf,不做任何改動,即不分配內存。
- 然后將得到的指針轉型
- 最后通過指針調用構造函數
-
總結:new會分配內存后調用構造函數,而placement new相當于只是調用構造函數。因此我們可以像下面這樣模擬new的行為:
-
容器的內存分配方式
當元素放入容器時,容器也需要為其分配一塊空間,但其不是用的new和delete,而是將其包裝在construct()和destroy()函數中 -
設計一個內存池
- 重載局部的operator new()
-
方法1:單獨多使用一些指針來將空閑塊連成鏈表
下面在節點中使用next指針來將小塊鏈接起來
void* A::operator new(size_t size) {cout << "局部new" << endl;A* p;if (!A::freeStore){//申請一大塊空間//A::freeStore = (A*)malloc(size * Chunk);A::freeStore = reinterpret_cast<A*>(new char[Chunk*size]);p = A::freeStore;//初始化p指針也指向頭節點//串成鏈表for (int i = 0; i < Chunk; i++){p->next = p + 1;//地址增大4,就是一個A的大小p = p->next;}p->next = NULL;}//把鏈表頭部的空閑塊拿出來用p = A::freeStore;A::freeStore = A::freeStore->next;return p; }
-
使用嵌入式指針:也就是指針臨時借用一下空閑塊里的空間,等到需要分配出去使用時就正常使用即可。
下面的rep和next占用同一片空間
class A { private://數據struct Airplane//占8字節{int miles;char type;}; private:union{Airplane rep;A* next;};static A* freeStore;//指向鏈表的頭部的指針static const int Chunk = 3;//內存池容納幾個 public:static void* operator new(size_t size);static void operator delete(void* ptr);void set(int m, char t)....void show().... };
-
- 重載局部的operator delete()
- 采用頭插法,將空閑塊插入到鏈表頭
void A::operator delete(void* ptr) {cout << "局部delete" << endl;//頭插法static_cast<A*>(ptr)->next = A::freeStore;A::freeStore = static_cast<A*>(ptr); }
- 采用頭插法,將空閑塊插入到鏈表頭
- c語言版本的內存池
- 先寫個宏定義
#define malloc(mp, size) _malloc(mp, size) #define free(mp, ptr) _free(mp, ptr)
- 定義一個大的內存塊,這里稱其為頁
typedef struct mempool_s {int block_size;//一小塊的大小int free_count;//該頁內剩余空閑塊的個數void *mem;//指向該頁首地址void *ptr;//指向該頁中最新創建的塊的地址(即下次要分配出去內存的塊) } mempool_t;
- 寫一個內存池初始化函數,將128個小塊串成鏈表
int memp_init(mempool_t *mp, size_t block_size) {printf("block_size: %ld\n", block_size);if (!mp) return -1;memset(mp, 0, sizeof(mempool_t));mp->block_size = block_size;mp->free_count = MEM_PAGE_SIZE / block_size;mp->mem = malloc(MEM_PAGE_SIZE);if(!mp->mem) return -1;mp->ptr = mp->mem;//把該頁中的128塊串成鏈表char *ptr = mp->ptr;//ptr指針指向第1塊for (int i = 0; i < mp->free_count; i++){//使用2級指針:一級指針ptr,(char**)ptr將其強轉為指向char*的指針,//*(char**)ptr為其指向的char*地址,將該地址賦值為ptr所指塊的下一塊地址*(char**)ptr = ptr + block_size;ptr += block_size;}*(char**)ptr = NULL;//最后一塊的前幾個字節保存的是NULLreturn 0; }
- 先寫個宏定義
- 最后寫內存分配與釋放的函數即可。釋放時同樣使用頭插法
- 重載局部的operator new()
- G2.9 alloc的大致流程:page8