與本地C++自己維護堆不同,C++/CLI中動態分配的內存是由CLR來維護的。當不需要堆時,CLR自動將其刪除回收,同時CLR還能自動地壓縮內存堆以避免產生不必要的內存碎片。這種機制能夠避免內存泄露內存碎片,被稱為垃圾回收,而由CLR管理的這種堆被稱為CLR堆。它由操作符gcnew創建。

由于垃圾回收機制會改變堆中對象的地址,因此不能在CLR堆中使用普通C++指針,因為如果指針指向的對象地址發生了變化,則指針將不再有效。為了能夠安全地訪問堆對象,CLR提供了跟蹤句柄(類似于C++指針)和跟蹤引用(類似于C++)引用。

一、跟蹤句柄

跟蹤句柄類似于本地C++指針,但能夠被CLR垃圾回收器自動更新以反映被跟蹤對象的新地址。同時不允許對跟蹤句柄進行地址的算術運算,也不能夠進行強制類型轉換。

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

關于跟蹤句柄的相關使用方法參見《C++/CLI學習入門(三):數組

二、跟蹤引用

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

跟蹤引用用%來定義,下面的例子創建了一個對堆棧上值對象的跟蹤引用:

int value = 10;
int% trackValue = value;

stackValue為value變量的引用,可以用stackValue來訪問value:

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

三、內部指針

C++/CLI還提供一種用關鍵字interior_ptr定義的內部指針,它允許進行地址的算術操作。必要時,該指針內存儲的地址會由CLR垃圾回收自動更新。注意,內部指針總是函數的局部自動變量。

下面的代碼定義了一個內部指針,它含有某數組中第一個元素的地址:

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

必須給interio_ptr指定內部指針指向的對象類型。此外還應該給指針進行初始化,如果不提供初始值,系統將其默認初始化為nullptr。

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

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

與本地C++指針一樣,內部指針可以進行算術計算。可以通過遞增或遞減來改變其包含的地址,從而引用后面或前面的數據項;還可在內部指針上加上或減去某個整數;可以比較內部指針。下面的例子展示了內部指針的用法:

- - - - - - - - - - - - - - - - <<== 華麗的分割線 ::開始==>> [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;
}
- - - - - - - - - - - - - - - - <<== 華麗的分割線 ::結束==>> [Ex4_19.cpp] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

輸出為

Total of data array elements = 18

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