Remember that the main use of C ++ / CLI is for developing class libraries for use by graphical interfaces / web services created in other .NET languages. Therefore, C ++ / CLI must support both reference and value types, because other .NET languages.
In addition, C # can have ref parameters that are also typed by value, this is not unique to C ++ / CLI and in no way makes value types equivalent to link types.
To answer questions in the code comments:
Am I making a copy or what?
Yes, SetValueTwo takes its parameter by value, so a copy is made.
Is it a one-time copy, even if value types do not have destructors?
Wrong. Value types can have destructors. Value types cannot have finalizers. Since this type of value has a trivial destructor, the C ++ / CLI compiler will not force it to implement IDisposable. In any case, if the parameter is an IDisposable value type, the C ++ / CLI compiler ensures that Dispose is called when the variable goes out of scope, like the stack semantics for local variables. This includes abnormal termination (exception) and allows the use of managed types with RAII.
AND
ValueStruct% ref = *gcnew ValueStruct;
and
ValueStruct^ ref = gcnew ValueStruct;
are allowed and put an instance of the boxed value type in a managed heap (which is not a heap at all, but a stack, however it is not a call stack where local variables are stored, so Microsoft decides to call it a heap, such as a memory area for dynamic allocation).
Unlike C #, C ++ / CLI can store typed descriptors for boxed objects.
If the tracking link refers to an instance of the value type on the stack or is embedded in another object, then the contents of the value type must be inserted into the field during link formation.
Tracking links can also be used with reference types, and the syntax for getting the descriptor is the same:
RefClass^ newinst = gcnew RefClass(); RefClass% reftoinst = *newinst; RefClass^% reftohandle = newinst; RefClass stacksem; RefClass^ ssh = %stacksem;
One thing that I can never fully recall is that the syntax does not match 100% compared to native C ++.
Declare link:
int& ri = i;
Declare a pointer:
int* pi;
Enter a pointer:
int* pi = &ri; // address-of native object DateTime^ dth = %dtr; // address-of managed object
Note that the unary operator address matches the reference notation in both standard C ++ and C ++ / CLI. This seems to contradict the tracking link cannot be used as a unary addressing operator (MSDN) , which I will return to in a second.
Firstly, inconsistency:
Create a link using a pointer:
int& iref = *pi; DateTime% dtref = *dth;
Note that the unary dereference operator is always * . This is the same as the designation of a pointer only in the home world, which is completely opposite to the address from which, as mentioned above, are always the same symbol as the reference notation.
Compiled Example:
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;
Now, about the unary address:
Firstly, the MSDN article is wrong when it says:
The following example shows that a tracking reference cannot be used as a unary addressing operator.
Correct statement:
% is the operator address for creating the tracking descriptor. However, its use is limited as follows:
The tracking descriptor must point to an object in the managed heap. Link types always exist on the managed heap, so there is no problem. However, value types and native types can be on the stack (for local variables) or embedded in another object (value type member variables). Attempts to create a tracking descriptor form a descriptor into a boxed copy of the variable: the descriptor is not associated with the source variable. As a consequence of the boxing process, which requires metadata that does not exist for native types, it is never possible to have a handle to track an instance of a native type.
Code example:
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
If System::Int32 not a value type, then I do not know what it is. Try System::DateTime , which is a non-primitive value type:
DateTime dt = DateTime::Now; DateTime^ dtbox = %dt;
It works!
As another unsuccessful restriction, primitive types that have a double identity (for example, native int and the type of the managed value System::Int32 ) are not processed correctly, the % operator (link to form tracking) cannot execute boxing, even if the .NET Name for type indicated.