C++中的符号^学习以及gcnew,gcroot学习 - C++/CLI

在写这篇文章前,我们需要先来了解学习一下, 什么是 C++/CLI

CLI - Common Language Infrastructure, 是通用语言基础架构,它是一种开发规范,它描述了允许多种高级语言在补充某些特定架构的情况下在不同的计算机平台上的可执行代码和运行时环境。

而 C++/CLI 是在.NET下用C++编程的方式, 和c#或者vb.net被使用的那样。

 句柄和指针

 在看C++代码时,发现有用到^符号,第一次见可能很困惑,不知道啥意思以及用来干嘛的. 我们知道,在C++中用*来表示一个指针. 那么,在C++/CLI中,我们用符号^来表示句柄. 那么句柄^和C++中的指针*有什么区别呢

1. *是C++中用来指定CRT heap上的原生指针

2. ^句柄,可以理解为安全指针,它位于托管堆上(gabarge collector heap), 和原生指针*不同的是,即使没有对它进行适当的删除,它也不会引起内存泄漏, 因为GC (Garbage Collector)会处理这些问题,并且它们没有一个固定的内存地址,所以在执行的时候它们会被移来移去.

 为了创建一个新的类型或值类型的引用,我们需要通过gcnew关键字来分配它:

System::Object ^testObj = gcnew System::Object();

 

 

在看C++写的代码时,发现有用到^符号,代码中的用法是这样的:
比如: 在C#代码中有个TestClass类,实现了接口ITestClass,然后里面有个创建单例的方法叫做 CreateInstance().现在我在C++中这么用:

Test.h
gcroot<ITestClass ^> m_ITestClass;

Test.cpp
m_ITestClass = TestClass::CreateInstance(); if ((ITestClass ^)m_ITestClass != nullptr) { }

gcroot是一个C++/CLI模板类,它简化了在C++/CLI类中保存托管类型的过程

gcroot是充当对托管对象或者值类型实例的引用, 并且在复制对象或值类型实例时执行所有工作. 通常,你需要使用GCHandle和.NET框架的一些C函数,都封装在gcroot中

GCHandle是.net中的,它主要做以下工作

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

当.net垃圾回收器运行时,它通过执行可达性分析来确定哪些对象还在使用。在查找指向对象的指针时,只分析托管堆,所以,如果你有一个从本机对象到托管对象的指针,则需要让垃圾回收器知道,以便它可以将其包含在可达性分析中,而且如果目标在压缩过程中移动,它可以更新指针.

.NET中的GCHandle类做到了这一点,C++/CLI是 GCHandle 的一个面向C++的包装器,它增加了类型安全和方便的语法

When the .NET garbage collector runs, it determine which objects are still in use by doing reachability analysis. Only the managed heap is analyzed while looking for pointers to objects, so if you have a pointer from a native object to a managed object, you need to let the garbage collector know, so it can include it in reachaability analysis, and so it can update the pointer if the target moves during compaction.

the .NET GCHandle class does this ,and C++/CLI(Common Language Infrastructure) is a C++ oriented wrapper for GCHanlde which adds type safety and convenient syntax.

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

在C++中通过将符号^放在类型名称的后面,用来指定该类型的句柄. 比如

String^ testVerb; => 这条语句就声明了一个可以存储String类型对象的地址, 名为testVerb的跟踪语句。 这条语句定义的testVerb变量就是String^类型的跟踪句柄. 

当像上面这样声明某个句柄时,系统将自动将其初始化为空值, 也就是说该句柄此时不引用任何对象.  也可以使用C++中的空指针关键字nullptr显示地将其设置为空值:

testVerb = nullptr;   ==> 这里特别需要注意: 此处不能像使用指针那样,在C++中使用0来表示空值. 因为如果这里,你用0来初始化句柄, 那么数值0将被转换为该句柄引用的对象类型, 而这个新对象的地址将被存入到该句柄中

 

在看代码的过程中,还看到C++中一个关键字的使用gcnew,而且使用这个关键字返回的类型就是带^符号的类型(返回跟踪句柄). 那么什么是gcnew呢

gcnew => 从拼写上可以看出,好像是gc和new的组合,显然gc = garbage collect  是垃圾回收器. new 就是新建一个对象  => C++/CLI(Common Language Infrastructure,通用语言框架) 中使用关键字gcnew来表示在托管堆(garbage collected heap)上分配内存, 它返回一个对象的(类型的)跟踪句柄^。  gcnew 和 new之间的区别如下

1.  gcnew返回的是一个句柄(Handle), 而new返回的是对象的实际的内存地址

2.  gcnew创建的对象由虚拟机托管(不需要程序员自己释放), 而new创建的对象必须自己来管理和释放

 我们看微软官方的解释:gcnew creates an instance of a managed type(reference or value type) on the garbage collected heap. The result of the evaluation of a gcnew expression is a handle(^) to the type being created

posted on 2023-05-11 15:54  新西兰程序员  阅读(846)  评论(0编辑  收藏  举报