類和動態記憶體分配(3)
定位new運算子號
//main.cpp
#include<iostream>
#include<string>
using namespace std;
const int BUF = 512;
class JustTest
{
private:
string words;
int number;
public:
JustTest(const string &s = "just testing", int n = 0)
{
words = s;
number = n;
cout << words <<" constructed\n" ;
}
~JustTest()
{
cout << words << " disconstructed\n";
}
void show()
{
cout << words << "," << number << endl;
}
};
void main()
{
{
char *buffer = new char[BUF];
JustTest *p1 = new(buffer)JustTest;
JustTest *p2 = new JustTest("badidea", 5);
cout << "memory addresses:\n";
cout << "buffer:" << (void*)buffer << endl;
//cout << "buffer:" << p1 << endl;
cout << "heap:" << p2 << endl;
cout << "memory contents:\n";
cout << "buffer:";
p1->show();
cout << "heap:";
p2-> show();
//delete p2;
//delete p1;
//delete buffer;
JustTest*p3, *p4;
p3 = new(buffer + sizeof(JustTest))JustTest("badidea2", 6);
p4 = new JustTest("head2", 8);
cout << "memory addresses:\n";
cout << "buffer:" << (void*)buffer << endl;
cout << "heap:" << p4 << endl;
cout << "memory contents:\n";
cout << "buffer:";
p3->show();
cout << "heap:";
p4->show();
delete p2;
delete p4;
delete[]buffer;
}
cout << "Done\n";
}
該程式使用new運算子建立了512位元組的記憶體緩衝區,然後new運算子在堆中建立了兩個JustTest物件,並試圖使用定位new運算子在記憶體緩衝區中建立兩個JustTest物件,最後使用delete釋放new分配的記憶體。
在使用第二個定位new運算子時存在兩個問題:
1.建立第二個物件時,定位new運算子使用一個新的物件來覆蓋第一個物件的記憶體單元。顯然如果類動態的為其成員分配記憶體將引發問題。
2.在delete用於p2和p4時,將自動呼叫p2和p4的解構函式,而將delete[]用於buffer時,不會為使用定位new運算子建立的物件呼叫解構函式。這也是我們為什麼只看p2和p4的析構資訊輸出。
因此,在使用定位new運算子時,必須提供兩個位於緩衝區的不同地址(確保不重疊):
JustTest *p1 = new(buffer)JustTest;
//新增偏移量
JustTest *p3 = new(buffer+sizeof)JustTest("badidea2", 6);
但是使用定位new運算子分配的物件記憶體,
delete p1;
delete p3;
是不允許的,原因是delete必須和常規的new運算子配合使用,但不能和定位new運算子配合使用。
指標p1指向的地址和bufeer相同,但是buffer是用new[]初始化的,因此必須使用delete[]來釋放。即使buffer是使用new而不是new[]初始化的 ,delete p1也將釋放buffer,而不是p1,因為new/delete系統知道分配的512位元組塊的buffer,但對定位new運算子對該記憶體塊做了何種處理一無所知。
由執行結果可以知道,p1和p3的解構函式並沒有呼叫,這種問題的解決方法是,顯示地位定位new運算子建立的物件呼叫解構函式。正常情況下是自動呼叫解構函式的,這是顯式呼叫解構函式的少數幾種情況之一:
p3->~JustTest();
p1->~JustTest();
需要注意的一點是正確的刪除順序。對於定位new運算子建立的物件,應與與建立順序相反的順序進行刪除。原因在於:晚建立的物件可能依賴於早建立的物件。另外,必須當所有的物件銷燬後,才能釋放用於儲存物件的緩衝區。