與本地C++自己維護(hù)堆不同,C++/CLI中動(dòng)態(tài)分配的內(nèi)存是由CLR來(lái)維護(hù)的。當(dāng)不需要堆時(shí),CLR自動(dòng)將其刪除回收,同時(shí)CLR還能自動(dòng)地壓縮內(nèi)存堆以避免產(chǎn)生不必要的內(nèi)存碎片。這種機(jī)制能夠避免內(nèi)存泄露內(nèi)存碎片,被稱為垃圾回收,而由CLR管理的這種堆被稱為CLR堆。它由操作符gcnew創(chuàng)建。

由于垃圾回收機(jī)制會(huì)改變堆中對(duì)象的地址,因此不能在CLR堆中使用普通C++指針,因?yàn)槿绻羔樦赶虻膶?duì)象地址發(fā)生了變化,則指針將不再有效。為了能夠安全地訪問(wèn)堆對(duì)象,CLR提供了跟蹤句柄(類似于C++指針)和跟蹤引用(類似于C++)引用。

一、跟蹤句柄

跟蹤句柄類似于本地C++指針,但能夠被CLR垃圾回收器自動(dòng)更新以反映被跟蹤對(duì)象的新地址。同時(shí)不允許對(duì)跟蹤句柄進(jìn)行地址的算術(shù)運(yùn)算,也不能夠進(jìn)行強(qiáng)制類型轉(zhuǎn)換。

凡是在CLR堆上創(chuàng)建的對(duì)象必須被跟蹤句柄引用,這些對(duì)象包括:(1)用gcnew操作符顯示創(chuàng)建在堆上的對(duì)象;(2)所有的引用數(shù)據(jù)類型(數(shù)值類型默認(rèn)分配在堆棧上)。注意:所有分配在堆上的對(duì)象都不能在全局范圍內(nèi)被創(chuàng)建。

關(guān)于跟蹤句柄的相關(guān)使用方法參見《C++/CLI學(xué)習(xí)入門(三):數(shù)組

二、跟蹤引用

跟蹤引用類似于本地C++引用,表示某對(duì)象的別名。可以給堆棧上的值對(duì)象、CLR堆上的跟蹤句柄創(chuàng)建跟蹤引用。跟蹤引用本身總是在堆棧上創(chuàng)建的。如果垃圾回收移動(dòng)了被引用的對(duì)象,則跟蹤引用將被自動(dòng)更新。

跟蹤引用用%來(lái)定義,下面的例子創(chuàng)建了一個(gè)對(duì)堆棧上值對(duì)象的跟蹤引用:

int value = 10;
int% trackValue = value;

stackValue為value變量的引用,可以用stackValue來(lái)訪問(wèn)value:

trackValue *= 5;
Console::WriteLine(value);	// Result is 50

三、內(nèi)部指針

C++/CLI還提供一種用關(guān)鍵字interior_ptr定義的內(nèi)部指針,它允許進(jìn)行地址的算術(shù)操作。必要時(shí),該指針內(nèi)存儲(chǔ)的地址會(huì)由CLR垃圾回收自動(dòng)更新。注意,內(nèi)部指針總是函數(shù)的局部自動(dòng)變量。

下面的代碼定義了一個(gè)內(nèi)部指針,它含有某數(shù)組中第一個(gè)元素的地址:

array<double>^ data = {1.5, 3.5, 6.7, 4.2, 2.1};
interior_ptr<double> pstart = %data[0];

必須給interio_ptr指定內(nèi)部指針指向的對(duì)象類型。此外還應(yīng)該給指針進(jìn)行初始化,如果不提供初始值,系統(tǒng)將其默認(rèn)初始化為nullptr。

內(nèi)部指針在指定類型時(shí)應(yīng)注意:可以包含堆棧上值類型對(duì)象的地址,也可以包含指向CLR堆上某對(duì)象句柄的地址,還可以是本地類對(duì)象或本地指針,但不能是CLR堆上整個(gè)對(duì)象的地址。也就是說(shuō),可以使用內(nèi)部指針存儲(chǔ)作為CLR堆上對(duì)象組成部分的數(shù)值類對(duì)象(如CLR數(shù)組元素)的地址,也可以存儲(chǔ)System::String對(duì)象跟蹤句柄的地址,但不能存儲(chǔ)String對(duì)象本身的地址。

interior_ptr<String^> pstr1;	// OK -- pointer to a handle
interior_ptr<String>  pstr2;	// ERROR -- pointer to a String object

與本地C++指針一樣,內(nèi)部指針可以進(jìn)行算術(shù)計(jì)算。可以通過(guò)遞增或遞減來(lái)改變其包含的地址,從而引用后面或前面的數(shù)據(jù)項(xiàng);還可在內(nèi)部指針上加上或減去某個(gè)整數(shù);可以比較內(nèi)部指針。下面的例子展示了內(nèi)部指針的用法:

- - - - - - - - - - - - - - - - <<== 華麗的分割線 ::開始==>> [Ex4_19.cpp] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Ex4_19.cpp : main project file.
#include "stdafx.h"
using namespace System;

int main(array<System::String ^> ^args)
{
	array<double>^ data = {1.5, 3.5, 6.7, 4.2, 2.1};
	interior_ptr<double> pstart = &data[0];
	interior_ptr<double> pend = &data[data->Length - 1];
	double sum = 0;

	while(pstart<=pend)
		sum += *pstart++;

	Console::WriteLine(L"Total of data array elements = {0}\n", sum);

	array<String^>^ strings = { L"Land ahoy!",
		L"Splice the mainbrace!",
		L"Shiver me timbers!",
		L"Never throw into the wind!"
	};

	for(interior_ptr<String^> pstrings = &strings[0]; pstrings-&strings[0] < strings->Length; ++pstrings)
		Console::WriteLine(*pstrings);

    return 0;
}
- - - - - - - - - - - - - - - - <<== 華麗的分割線 ::結(jié)束==>> [Ex4_19.cpp] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

輸出為

Total of data array elements = 18

Land ahoy!
Splice the mainbrace!
Shiver me timbers!
Never throw into the wind!