在處理記憶體配置的時候,C++程式員會用new操作符(operator new)來分配記憶體,並用delete操作符(operator delete)來釋放記憶體。這是一個new操作符的例子。 class CTest { /* 成員函數和成員資料 */ }; // . . . 代碼 // 分配一個對象 CTest * pTest = new Test; // 分配一個有十個對象的數組 (CTest 要有預設建構函式(default constuctor)) CTest * p10Tests = new Test[ 10]; 雖然這種寫法在大多數時候都工作得很好,但還是有些情況下使用new是很煩人的,比如當你想重新分配一個數組或者當你想在預分配的記憶體上構造一個對象的時候。 比如第一種情況,重新分配一個數組效率是很低的: // 分配一個有10個對象的數組 CTest * pTests = new Test[ 10]; // . . . // 假設現在我們需要11個對象 CTest * pNewTests = new Test[ 11]; // . . . 我們必須把原來的對象拷貝到新分配的記憶體中 for ( int i = 0; i < 10; i++) pNewTests[ i] = pTests[ i]; delete pTests; pTests = pNewTests; 如果你想在預分配的記憶體上建立對象,用預設的new操作符是行不通的。要解決這個問題,你可以用placement new構造。它允許你構造一個新對象到預分配的記憶體上: // buffer 是一個void指標 (void *) // 用方括弧[] 括起來的部分是可選的 [CYourClass * pValue = ] new( buffer) CYourClass[( parameters)]; 下面是一些例子: #include <new> class CTest { public: CTest() {} CTest( int) {} /* 代碼*/ }; int main(int argc, char* argv[]) { // 由於這個例子的目的,我們不考慮記憶體對齊問題 char strBuff[ sizeof( CTest) * 10 + 100]; CTest * pBuffer = ( CTest *)strBuff; // 預設構造 CTest * pFirst = new(pBuffer) CTest; // 預設構造 CTest * pSecond = new(pBuffer + 1) CTest; // 帶參數的構造; // 不理會返回的指標 new(pBuffer + 2) CTest( 5); // 帶參數的構造 CTest * pFourth = new( pBuffer + 3) CTest( 10); // 預設構造 CTest * pFifth = new(pBuffer + 4) CTest(); // 構造多個元素(預設構造) CTest * pMultipleElements = new(pBuffer + 5) CTest[ 5]; return 0; } 當你有自己的記憶體緩衝區或者在你實現自己的記憶體配置策略的時候,placement new會很有用。事實上在STL中廣泛使用了placement new來給容器分配記憶體;每個容器類都有一個模版參數說明了構造/析構對象時所用的分配器(allocator)。 在使用placement new的時候,你要記住以下幾點:
- 加上標頭檔#include <new>
- 你可以用placement new構造一個數組中的元素。
- 要析構一個用placement new分配的對象,你應該手工調用解構函式(並不存在一個“placement delete”)。它的文法如下:
pFirst->~CTest(); pSecond->~CTest(); 前段事件,我問過關於placement new的問題,一位仁兄講了一些道理,他說道: ::棧上的對象(注意,是類對象,char類型就無需了,後面還會提到)保證放在對齊地址上. 但是,個人實驗了一下,發現並不是這樣 例如: int main() { char c1 = 'A' ; char c2 = 'B' ; char c3 = 'C' ; char c4 = 'D' ; char c5 = 'E' ; //-------- 驗證這四個地址是否是 4 的倍數 --------------// if ( ((int)(&c1)) % 4 == 0 ) cout << "c1:Yes" << endl ; if ( ((int)(&c2)) % 4 == 0 ) cout << "c2:Yes" << endl ; if ( ((int)(&c3)) % 4 == 0 ) cout << "c3:Yes" << endl ; if ( ((int)(&c4)) % 4 == 0 ) cout << "c4:Yes" << endl ; if ( ((int)(&c5)) % 4 == 0 ) cout << "c5:Yes" << endl ; cout << (int)(&c1) << endl // 輸出四個字元所在的地址(輸出結果都是 4 的倍數) << (int)(&c2) << endl << (int)(&c3) << endl << (int)(&c4) << endl << (int)(&c5) << endl ; } ----------------------------- 上面的執行結果在VC下運行都是 4 的倍數 -------------- --> 問題1:連棧上分配的空間地址都是 4 的倍數,那就說明系統分配的空間都是 4 的倍數吧??? --> 問題2:如果萬一,如果放一個對象的地址不是4的倍數,那麼會出現什麼情況??可以給簡單說一下嗎? --> 問題3:地址對齊的通用性??? ------------- 程式1: Class C1 { int i ; char c ; } ; cout << sizeof(C1) << endl ;// 輸出結果: 8 (是 4 的倍數) 程式2: class C2 { char c1 ; char c2 ; } ; cout << sizeof(C2) << endl ;// 輸出結果:2 ( 上一個中char類型也給了4個位元組,怎麼這個地方都給了一個位元組??) --> 問題4:由上面的程式2 引出下面的程式 class C2// sizeof(C2) =2 ,在VC實驗下的結果,不是 4 { char c1 ; char c2 ; } ; //----------用placement new方法建立對象---------------- void *ptr = operator new(100) ;// 分配記憶體 C2 *POINTER = (C2*)ptr ;// 類型轉換 String *str1 = new (POINTER) C2() ;// 建立一C2對象 String *str2 = new (POINTER+1) C2() ;// 再建立一個對象 String *str3 = new (POINTER+2) C2() ;// 再建立一個對象 cout << (int)(str1) << endl// 結果:3608720( 是4的倍數) << (int)(str2) << endl // 結果:3608722(不是4的倍數)!! << (int)(str3) << endl ;// 結果:3608724(不是4的倍數)!! |