与本地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 : 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; }
输出为
Total of data array elements = 18
Land ahoy!
Splice the mainbrace!
Shiver me timbers!
Never throw into the wind!