C++CLI解析之基于堆栈的对象与跟踪引用

C++CLI解析之基于堆栈的对象与跟踪引用,第1张

C++CLI解析之基于堆栈的对象与跟踪引用,第2张

在托管堆上分配对象实例似乎是使用托管扩展C++、C#、J#和VB.NET程序员的方法,而使用本地C++的程序员不仅可以在堆上分配内存,甚至更习惯于使用基于堆栈的对象实例。

现在回顾先前定义的点引用类,然后查看以下变量定义:

点p1,p2(3,4);

从本地C++的角度来看,p1和p2应该是基于栈的引用类Point的实例,即使从一般的角度来看。P1由默认的构造函数初始化,而p2由接受x和y坐标的构造函数初始化。从实现的角度来看,Point是一个自包含类型(也就是说,它不包含任何指针或句柄)。然而,作为一个引用类的实例,它仍然在CLI运行时的控制之下,并且将在必要时被垃圾收集——因此,不可能定义一个引用类的静态或全局实例。

同时,sizeof不能应用于引用类实例的表达式,因为sizeof是在编译时计算的,Point对象的大小要到运行时才能确定;但是,sizeof可以应用于句柄,因为它的大小已经在编译时确定了。

此外,您不能定义基于堆栈的CLI阵列实例。

跟踪参考

C++可以通过&定义对象的别名。例如,对于任何本地类N,您可以编写以下代码:

N n1
N & N2 = n1;

引用在定义时必须初始化,并且在整个生命周期中被锁定引用同一个对象,也就是说,它的值不会改变。引用引用类的实例与引用局部类基本相同,但语法不同。

在程序执行过程中,引用类的实例会在内存中“移动”,所以有必要对其进行跟踪,但是局部指针和引用无法胜任这项工作(尤其是不能对引用类的一个实例使用地址取数符号&)。因此,C++/CLI相应地提供了用于跟踪的句柄和引用——这里简称为跟踪引用。例如,您可以定义一个跟踪。

点% p3 = p2

参考的存储器存储模式必须是自动的。另外,虽然本地对象不会在内存中“移动”,但是在上面的n2中,在C++/CLI中不能用%代替&使用,%是for,就像本地C++中的& for *一样。

请看下面的代码:

Point^ hp = gcnew Point(2,5);
Point % P4 = * HP;
Point% p5 = *gcnew Point(2,5);

这里hp是一个点的句柄,p4是这个句柄的别名。虽然句柄不是指针,但是一元*运算符也可以用来取消句柄的引用。(在C++/CLI标准的制定过程中,曾经有过是否引入一元运算符代替*的讨论。相反的观点认为*解引用句柄或指针在编写模板时有很大的价值。当然,即使hp有了新的值,p4在这里仍然是同一点的别名。此外,当对象有句柄或跟踪引用时,它不能被垃圾收集器收集。

再来看p5。我们可以取消引用gcnew返回的句柄。尽管几乎每种类型的引用类都可以被解引用,但有两种类型的句柄不能被解引用:System::String和array。
获取句柄运算符

如果要将p1的值写入标准输出,代码应该如下所示:

Console::WriteLine("p1 is {0} ",P1);

但是,这是无法编译的,因为WriteLine没有可以接受Point的重载版本。如前所述,任何值类型(如int、long、double)的表达式都将通过“装箱”过程自动转换为Object^。虽然p1看起来更像是值类型的实例,但实际上不是。它是引用类的实例,所以需要修改代码如下:console:: writeline ("P1是{0} ",% P1);

通过使用一元%运算符,我们创建了对象p1的句柄,因为每个引用类最终都是从System::Object继承的,而且WriteLine也有一个重载版本,其第二个参数可以接受Object,所以%p1的Point^被转换为object,并显示p1的对应值。注意这里没有装箱,但是这个操作符不能应用于本地类的实例。

GC-左值

C++标准中定义并使用了术语lvalue,而C++/CLI标准中增加了术语gc-lvalue,它指的是“引用CLI堆中的对象或包含该对象的数值成员的表达式”。如果有gc-lvalue的句柄,可以使用一元*运算符生成一个GC-lvalue;而且trace引用也是一个gc-lvalue,当%h中的h是句柄时也可以生成一个gc-lvalue。(因为存在从左值到GC-左值的标准转换,所以跟踪引用可以绑定到任何GC-左值或左值。)

位律师回复
DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
白度搜_经验知识百科全书 » C++CLI解析之基于堆栈的对象与跟踪引用

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情