簡易內存池與new定位分配

如何理解new的定位表達式?它有什麼用處呢?如何實現new只調用類的構造函數呢?

首先,我們應該明確new的操作,可以分爲兩個步驟:

(1)計算所需內存大小,從空閒堆中分配內存;

(2)調用類的構造函數對這塊內存進行初始化。


可是,如果我們在某個函數裏要生成某個複雜類,而且要多次調用new和delete,這種內存上的分配和釋放都會帶來效率問題,所以我們可以利用new的定位表達式來讓new 對象固定在某個空閒區,不許要內存計算。只需要調用構造函數初始化即可。

new (place_address) class-type

例如我們有Apple類

class Apple{
public:
	int i;
	Apple():i(0){

		cout<<i<<":called construct!\n";
		i++;
	}
	Apple(int _i):i(_i){
		cout<<"called construct!\n";
	}
	~Apple(){
		cout<<i<<":called deconstruct!\n";
	}
	void print(){
		cout<<i<<endl;
	}
};

首先,預分配一快區域

char *buf = new char[sizeof(Apple)*number];

然後,我們動態分配的時候加上該內存區域即可

Apple *p1 = new (buf)Apple;
會自動定位在該區域

如果後面再次定義

p1 = new (buf)Apple;

則又從buf開始位置初始化,所以會覆蓋上一個對象!!!如下:

#include <iostream>
#include <string>
#include <new>

using namespace std;
class Apple{
public:
	int i;
	Apple():i(0){

		cout<<i<<":called construct!\n";
		i++;
	}
	Apple(int _i):i(_i){
		cout<<"called construct!\n";
	}
	~Apple(){
		cout<<i<<":called deconstruct!\n";
	}
	void print(){
		cout<<i<<endl;
	}
};

int main(){

	char *buf = new char[sizeof(Apple)*2];

	Apple *p1 = new (buf)Apple;
	Apple *p2 = new (buf)Apple;
	cout<<p1<<" "<<p2<<" "<<sizeof(Apple)<<endl;
	cout<<(void*)buf;

	delete []buf;
	return 0;
}

0:called construct!
0:called construct!
0x20d0010 0x20d0010 4
0x20d0010
輸出結果發現,兩次分配地址和buf是一致的!!

如何main函數改成

int main(){

	char *buf = new char[sizeof(Apple)*2];

	/*Apple *p1 = new (buf)Apple;
	Apple *p2 = new (buf)Apple;*/
	Apple *p = new (buf)Apple[2];
	cout<<&p[0]<<" "<<&p[1]<<" "<<sizeof(Apple)<<endl;
	cout<<(void*)buf;

	delete []buf;
	return 0;
}

輸出:

0:called construct!
0:called construct!
0x1883038 0x188303c 4
0x1883010
我們看到,這種數組就會順延了

喜歡bug的我,想如果數組長度大於我們預分配的長度呢?

大家可以做個實驗,我機子上還是順延,繼續把沒有預分配的後面內存也拿來了,和上面是一樣,但希望大家別這樣,我們這裏程序太短,如果是分配較多的其他對象,很有可能就會唄覆蓋了。

記得#include <new>才能使用定位運算哦

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章