C ++ / CLI中的跟踪引用 [英] Tracking reference in C++/CLI

查看:188
本文介绍了C ++ / CLI中的跟踪引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人可以向我解释下列程式码片段吗?

Can someone please explain me the following code snippet?

value struct ValueStruct {
    int x;
};

void SetValueOne(ValueStruct% ref) {
    ref.x = 1;
}

void SetValueTwo(ValueStruct ref) {
    ref.x = 2;
}

void SetValueThree(ValueStruct^ ref) {
    ref->x = 3;
}

ValueStruct^ first = gcnew ValueStruct;
first->x = 0;
SetValueOne(*first);

ValueStruct second;
second.x = 0;
SetValueTwo(second); // am I creating a copy or what? is this copy Disposable even though value types don't have destructors?

ValueStruct^ third = gcnew ValueStruct;
third->x = 0;
SetValueThree(third); // same as the first ?

我的第二个问题是:有什么理由拥有这样的东西吗?:

And my second question is: is there any reason to have something like that?:

ref struct RefStruct {
    int x;
};

RefStruct% ref = *gcnew RefStruct;
// rather than:
// RefStruct^ ref = gcnew RefStruct;

// can I retrieve my handle from ref?
// RefStruct^ myref = ???

更重要的是:我看不到值类型和ref类型之间的区别,处理程序;(

What is more: I see no difference between value type and ref type, since both can be pointed by handler ;(

推荐答案

请记住,C ++ / CLI的主要用途是开发类库以供GUI /因此C ++ / CLI必须同时支持引用和值类型,因为其他.NET语言都支持。

Remember that the primary use of C++/CLI is for developing class libraries for consumption by GUIs / web services built in other .NET languages. So C++/CLI has to support both reference and value types because other .NET languages do.

此外,C#可以有 ref 参数也是值类型,这不是C ++ / CLI独有的,它不以任何方式使值类型等同于引用类型。

Furthermore, C# can have ref parameters that are value typed as well, this isn't unique to C++/CLI and it doesn't in any way make value types equivalent to reference types.

要回答代码中的问题:


我是创建副本还是什么?

am I creating a copy or what?

是,SetValueTwo以值为参数,因此会生成副本。

Yes, SetValueTwo takes its parameter by value, so a copy is made.


是这个副本即使值类型没有析构函数,也是一次性的。

is this copy Disposable even though value types don't have destructors?

不正确。值类型可以有析构函数。值类型不能有finalizer。由于这个特定的值类型有一个简单的析构函数,C ++ / CLI编译器不会导致它实现IDisposable。在任何情况下,如果参数是IDisposable值类型,C ++ / CLI编译器将确保当变量超出作用域时调用Dispose,就像局部变量的堆栈语义。这包括异常终止(抛出异常),并允许托管类型与RAII一起使用。

Incorrect. Value types can have destructors. Value types cannot have finalizers. Since this particular value type has a trivial destructor, the C++/CLI compiler will not cause it to implement IDisposable. In any case, if a parameter is an IDisposable value type, the C++/CLI compiler will ensure that Dispose is called when the variable goes out of scope, just like stack semantics for local variables. This includes abnormal termination (thrown exception), and allows managed types to be used with RAII.

两者

ValueStruct% ref = *gcnew ValueStruct;

ValueStruct^ ref = gcnew ValueStruct;

,并在托管堆(不是堆但是它是一个堆栈,但它不是调用堆栈存储的局部变量,所以Microsoft选择将其称为堆像本地内存区域动态分配)。

are allowed, and put a boxed value type instance on the managed heap (which isn't a heap at all, but a stack, however it is not the call stack where local variables are stored, so Microsoft chooses to call it a heap like the native memory area for dynamic allocation).

与C#不同的是,C ++ / CLI可以保持对框形对象的类型处理。

Unlike C#, C++/CLI can keep typed handles to boxed objects.

如果跟踪引用是堆栈上的值类型实例或嵌入到另一个对象,那么值类型内容必须在形成引用的过程中加框。

If a tracking reference is to a value type instance on the stack or embedded in another object, then the value type content has to be boxed in the process of formed the reference.

跟踪引用也可以与引用类型一起使用,并且语法获取句柄是相同的:

Tracking references can also be used with reference types, and the syntax to obtain a handle is the same:

RefClass^ newinst = gcnew RefClass();
RefClass% reftoinst = *newinst;
RefClass^% reftohandle = newinst;

RefClass stacksem;
RefClass^ ssh = %stacksem;

我永远不能完全记住的一件事是,语法不是100%到本地C ++。

One thing that I can never seem to remember completely is that the syntax isn't 100% consistent compared to native C++.

声明引用:

int& ri = i; // native
DateTime% dtr = dt; // managed tracking reference

声明一个指针:

int* pi; // native
Stream^ sh; // tracking handle

形成指针:

int* pi = &ri; // address-of native object
DateTime^ dth = %dtr; // address-of managed object

请注意,一元运算符address-标准C ++和C ++ / CLI中的符号。这似乎与跟踪引用不能用作一元接收地址运算符(MSDN )

Note that the unary address-of operator is the same as the reference notation in both standard C++ and C++/CLI. This seems to contradict a tracking reference cannot be used as a unary take-address operator (MSDN) which I'll get back to in a second.

首先,不一致:

从指针形式引用:

int& iref = *pi;
DateTime% dtref = *dth;

注意,一元取消引用操作符总是 * 。它与仅在本地世界中的指针表示法相同,它与地址完全相反,如上所述,它们总是与参考符号相同的符号。

Note that the unary dereference operator is always *. It is the same as the pointer notation only in the native world, which is completely opposite of address-of which, as mentioned above, are always the same symbol as the reference notation.

可编译的示例:

DateTime^ dth = gcnew DateTime();
DateTime% dtr = *dth;

DateTime dt = DateTime::Now;
DateTime^ dtbox = %dt;

FileInfo fi("temp.txt");
// FileInfo^ fih = &fi;  causes error C3072
FileInfo^ fih = %fi;

现在,关于一元地址:

首先,MSDN文章是错误的:

First, the MSDN article is wrong when it says:


以下示例显示,跟踪引用不能用作一元-address运算符。

The following sample shows that a tracking reference cannot be used as a unary take-address operator.

正确的语句是:

是创建跟踪句柄的运算符的地址。但是其使用受到以下限制:

% is the address-of operator for creation of a tracking handle. However its use is limited as follows:

跟踪句柄必须指向托管堆上的对象。引用类型总是存在于托管堆上,所以没有问题。但是,值类型和本机类型可以在堆栈(对于局部变量)或嵌入在另一个对象(值类型的成员变量)中。尝试形成跟踪句柄将形成对变量的盒装副本的句柄:句柄未链接到原始变量。作为拳击过程的结果,其需要对于原生类型不存在的元数据,所以不可能具有对原生类型的实例的跟踪句柄。

A tracking handle must point to an object on the managed heap. Reference types always exist on the managed heap so there is no problem. However, value types and native types may be on the stack (for local variables) or embedded within another object (member variables of value type). Attempts to form a tracking handle will form a handle to a boxed copy of the variable: the handle is not linked to the original variable. As a consequence of the boxing process, which requires metadata which does not exist for native types, it is never possible to have a tracking handle to an instance of a native type.

示例代码:

int i = 5;
// int^ ih = %i;  causes error C3071

System::Int32 si = 5;
// System::Int32^ sih = %si; causes error C3071
// error C3071: operator '%' can only be applied to an instance 
//              of a ref class or a value-type

如果 System :: Int32 不是值类型,那么我不知道是什么。让我们尝试 System :: DateTime 这是一个非原始值类型:

If System::Int32 isn't a value type then I don't know what is. Let's try System::DateTime which is a non-primitive value type:

DateTime dt = DateTime::Now;
DateTime^ dtbox = %dt;

这很有效!

不幸的限制,具有双重身份的原始类型(例如,本地 int 和托管值类型 System :: Int32 正确处理,(表单跟踪引用)运算符无法执行加框,即使已给定类型的.NET名称。

As a further unfortunate restriction, primitive types which have dual identity (e.g. native int and managed value type System::Int32) are not handled correctly, the % (form tracking reference) operator cannot perform boxing even when the .NET name for the type is given.

这篇关于C ++ / CLI中的跟踪引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆