转换指南 —— 从 ISO-C++ 到 C++/CLI v1.0
3. 新的指针 —— 跟踪句柄,内部指针,图钉指针... 7
1. CLI关键字
|
关键字 |
说明 |
CLR Data Type Keywords |
ref class ref struct |
Defines a CLR reference class 定义一个CLR引用类型 |
|
value class value struct |
Defines a CLR value class 定义一个CLR值类型 |
|
interface class interface struct |
Defines a CLR interface 定义一个CLR接口类型 |
|
enum class enum struct |
Defines a CLR enumeration 定义一个CLR枚举类型 |
|
property |
Defines a CLR property 定义一个CLR属性 |
|
delegate |
Defines a CLR delegate 定义一个CLR委托 |
|
event |
Defines a CLR event 定义一个CLR事件 |
|
|
|
Override Specifiers |
abstract |
Indicates functions or classes are abstract 声明这个函数或者类是抽象的(不能实例化) |
|
new |
Indicates that a function is not an override of a base class version 声明该函数不是基类版本的复写 |
|
override |
Indicates that a method must be an override of a base-class version 声明该函数是基类版本的复写(在修饰虚函数时,override和new两者必须选择其一) |
|
sealed |
Prevents classes from being used as base classes 声明该类不能被继承 |
|
|
|
Keywords for Generics |
generic |
Defines a generic type 定义一个泛型 |
|
where |
Specifies the constraints of a generic typef 规定泛型的类型限制 |
|
|
|
Miscellaneous New Keywords |
finally |
Indicates default exception handlings behavior 声明一个缺省异常处理块 |
|
for each |
Enumerate elements of a collection. 枚举集合类内的元素 |
|
gcnew |
Allocates types on the garbage-collected heap 在托管堆内为类型分配存储空间 |
|
initonly |
Indicates a member can only be initialized at declaration or in a static constructor 指出一个声明同时初始化或者在类静态构造函数中初始化的类成员 |
|
literal |
Creates a literal variable 创建一个文字变量 |
|
nullptr |
Indicates that a handle or pointer does not point at an object 用来标识一个空指针或者空句柄 |
|
|
|
Non-Keyword Language Constructs |
array |
Type for representing CLR arrays CLR数组 |
|
interior_ptr |
Points to data inside reference types. 内部指针,用于获得引用类别内部的数据成员的地址 |
|
pin_ptr |
Points to CLR reference types to temporarily suppress the garbage collection system 图钉指针,用于锁住CLR引用类别对象的地址,防止垃圾收集器回收或者搬移 |
|
safe_cast |
Determines and executes the optimal casting method for CLR types 用于CLR类型的类型转换 |
|
typeid |
Retrieves a System.Type object describing the given type or object 获得一个CLR类型的类型信息 |
|
|
|
New C++ Operators |
^ |
Indicates a handle to an object located on the garbage-collected heap 一个跟踪句柄的声明,跟踪句柄是一个指向分配在托管堆内的CLR类型对象的指针 |
|
% |
Indicates a tracking reference 用来标识一个跟踪引用 |
C++ 的内存布局分为两大块,堆和栈,一个C++ 类型的变量不是分配在堆上(动态内存分配)就是分配在栈上(静态内存分配),下面是一段示例代码和相关的内存分配布局图。
class NativeObject
{
public:
int _x;
};
//
NativeObject no;
no._x = 100;
NativeObject* pno = new NativeObject();
pno->_x = 101;
FIG 1 C++ 程序的内存布局
而C++/CLI编写的托管应用程序,CLR管理的内存布局除了原来的堆(有专门的术语Native Heap 原生堆来称呼它)和栈外,还另外增加了一个托管堆(CLR Heap or Managed Heap)。CLR引用类型对象会被分配在托管堆上,无论是使用动态分配方式还是静态分配方式(当使用静态分配方式的时候,CLR引用类型对象有着栈对象一样的语义行为,但是实际的内存分配是在托管堆而不是在栈上),而CLR值类型对象在使用动态分配方式的时候会被分配在托管堆上,而使用静态分配方式的时候会被分配在栈上(CLR值类型跟ISO-C++的类型,在分配方式和语义上都十分类似,而CLR引用类型则有较大的差别)。在托管堆里的对象,它们由垃圾收集器管理,被垃圾收集器回收或者搬移。
ref class ClrRefObject
{
public:
int _x;
};
value class ClrValueObject
{
public:
int _x;
};
ClrRefObject cro;
cro._x = 100;
ClrRefObject^ hcro = gcnew ClrRefObject();
hcro->_x = 101;
ClrValueObject cvo;
cvo._x = 102;
ClrValueObject^ hcvo = gcnew ClrValueObject();
hcvo->_x = 103;
FIG2 CLI程序的内存布局
CLR类型对象的内存分配方式使得CLI需要提供新的指针语法与ISO-C++指针区别开来。实际上在CLI里面,所提供的有着近似指针行为,用来操作对象的东西,正式的名称叫做跟踪句柄(Tracking Handle)。更接近ISO-C++指针的等同物是interior_ptr和pin_ptr。
3.1 跟踪句柄的语义
跟踪句柄的名称也说明它与传统的指针有着很大的区别,严格的说它是一个受控的更安全的对象标识符,它只具备访问CLR类型对象成员的指针语义,其它的传统指针语义都被摒弃了(C/C++里面的指针具备非常复杂的语义行为,使得编译器无法对它进行严格的检查,也是导致很多“内存非法访问”问题的原因):
a) 在CLI中,跟踪句柄只能指向一个CLR类型的整对象,它不能指向对象中的某个成员。
b) 跟踪句柄的值是无意义的,这意味着所有的指针算术对跟踪句柄来说都是非法的(加法,减法,大小比较等等),因为跟踪句柄的指向就只能是一个CLR<