标准C++是自己维护堆,而C++/CLI则是由CLR来维护的。
不需要时,CLR自动将其删除回收,同时CLR还能自动压缩内存堆以避免产生不必要的内存碎片。C++/CLI的这种内存机制,可以避免内存泄漏和产生内存碎片,被称为垃圾回收。而由CLR管理的这种堆被称为CLR堆,由gcnew 操作符创建的。
由于垃圾回收机制会改变堆中的对象的地址,所以不能在CLR堆中使用普通的C++指针。为此,CLR提供了跟踪句柄和跟踪引用来安全地访问堆中的对象。
跟踪句柄:类似于本地C++的指针。存储着某个对象的地址,在CLR压缩堆过程中时将改变对象的实际地址,由垃圾回收器自动更新跟踪句柄所包含对象的地址,所以,在程序中不能够像本地C++指针那样执行地址的算术运算,也不允许对跟踪句柄进行强制类型转换。
声明一个跟踪句柄时,可以将符号"^"添加到类型名称的后面用于指定该类型的句柄变量。声明后,系统自动初始化为空值,表示该句柄未引用任何对象。或者通过nullptr显示地
将跟踪句柄初始化为空值。
String ^name; //
String ^word=nullptr;
String^ saying=L"Hello World!";
如果在基本数据类型后添加 "^" 符号,那么将创建一个值类型的跟踪句柄,并且将在CLR堆上创建该类型的变量。由于此时定义的变量相当于C++的指针,所以此时变量不能参与算术运算。 需要通过“*” 运算符对地址求值。
int ^result=0; //警告:不能用0来初始化句柄
result=2*(*value)+15; //或者:*result=2*(*value)+15;
int result2;
*result2=2*(*value)+15;//错误,result2并未世界引用实际的对象
因此,凡是在CLR堆上创建的对象都必须被跟踪句柄所引用。
凡是所有分配在堆上的对象都不能在全局范围内被创建,例如,在程序中不能够创建一个String类型的全局变量。
跟踪引用:类似于本地C++引用,用于表示某对象的别名。可以给堆栈上的值对象,CLR堆上的跟踪句柄创建跟踪引用。
C++/CLI通过"%"符号定义句柄的跟踪引用。
int value=10;
int %travelvalue=value;
travelvalue*=5;
Console::WriteLine(value); //value=50;
跟踪引用本身永远是在堆栈上创建的,如果垃圾回收移动了被引用的对象,则跟踪引用被自动更新。