1. 程式人生 > >類和動態記憶體分配(3)

類和動態記憶體分配(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運算子建立的物件,應與與建立順序相反的順序進行刪除。原因在於:晚建立的物件可能依賴於早建立的物件。另外,必須當所有的物件銷燬後,才能釋放用於儲存物件的緩衝區。