This sample shows that a handle can be dereferenced and that a member can be accessed via a dereferenced handle.
// The ^ handle // compile with: /clr #include "stdafx.h"
using namespace System;
value struct DataCollection { private: int Size; array<String^>^ x; public: DataCollection(int i) : Size(i) { x = gcnew array<String^>(Size); for (int i = 0 ; i < Size ; i++) x[i] = i.ToString(); } void funct(int Item) { if (Item >= Size) { System::Console::WriteLine("Cannot access array " "element {0}, coz the size is {1}", Item, Size); return; } else System::Console::WriteLine("Array value: {0}", x[Item]); } };
void funct(DataCollection y, int Item) { y.funct(Item); }
int main() { DataCollection ^ aob = gcnew DataCollection(10); // dereference a handle, return handle's object funct(*aob, 7); // access member via dereferenced handle (*aob).funct(11); return 0; }
Output: |

This sample shows that a native reference (&) can’t bind to an int member of a managed type, as the int may be stored in the garbage collected heap, and native references don’t track object movement in the managed heap. The fix is to use a local variable, or to change & to %, making it a tracking reference.
// The ^ handle example
// compile with: /clr
#include "stdafx.h"
using namespace System;
ref struct Astruct
{
// Change the & to % to correct the error
void Test(unsigned int &){Console::WriteLine("In Test()...");}
void Test2(unsigned int %){Console::WriteLine("In Test2()...");}
unsigned int i;
};
int main()
{
Astruct aob;
aob.i = 9;
aob.Test(aob.i); // C2664
aob.Test2(aob.i); // OK
unsigned int j = 0;
aob.Test(j); // OK
return 0;
}
Output:
1>.\Animal1.cpp(19) : error C2664: 'Astruct::Test' : cannot convert parameter 1 from 'unsigned int' to 'unsigned int &'
1> An object from the gc heap (member of a managed class) cannot be converted to a native reference
Output when:
void Test(unsigned int &){Console::WriteLine("In Test()...");}
Changed to:
void Test(unsigned int %){Console::WriteLine("In Test()...");}

gcnew
gcnew keyword 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. Consider the following program example.
Program Example
// gcnew keyword
// compile with: /clr
#include "stdafx.h"
using namespace System;
ref struct Message
{
System::String ^ sender, ^ receiver, ^ data;
};
int main()
{
Message ^ h_Message = gcnew Message;
h_Message->sender = "Test sender";
h_Message->receiver = "Test receiver";
h_Message->data = "Test data";
Console::WriteLine("sender = {0}", h_Message->sender);
Console::WriteLine("receiver = {0}", h_Message->receiver);
Console::WriteLine("data = {0}", h_Message->data);
return 0;
}
Output:

It is possible to create an instance of a managed type, where the managed type contains a nested type other than a reference type as shown in the following program example.
// gcnew keyword
// compile with: /clr
#include "stdafx.h"
using namespace System;
ref class MyClass
{
public:
void Test() {Console::WriteLine("In Test(). Some string...");}
// nested...
value class Value_Nested_Class
{
public:
int i;
};
};
int main()
{
// Instantiate new object...
MyClass ^ h_MyClass = gcnew MyClass;
MyClass::Value_Nested_Class yobj;
yobj.i = 100;
System::Console::WriteLine("yobj.i = {0}", yobj.i);
return 0;
}
Output:

Declare Handles in Native Types
You cannot declare a handle type in a native type. vcclr.h provides the type-safe wrapper template gcroot, to refer to a CLR object from the C++ heap. This template lets you embed a virtual handle in a native type and treat it as if it were the underlying type. The gcroot template is implemented using the facilities of the value class System::Runtime::InteropServices::GCHandle, which provides "handles" into the garbage-collected heap. Note that the handles themselves are not garbage collected and are freed when no longer in use by the destructor in the gcroot class (this destructor cannot be called manually). If you instantiate a gcroot object on the native heap, you must call delete on that resource. The runtime will maintain an association between the handle and the CLR object, which it references. When the CLR object moves with the garbage-collected heap, the handle will return the new address of the object. A variable does not have to be pinned before it is assigned to a gcroot template.
Program Example
The following example shows how to create a gcroot object on the native stack.
// gcroot keyword
// compile with: /clr
#include "stdafx.h"
#include <vcclr.h>
using namespace System;
// native C++ class definition...
class CppClass
{
public:
// can use str as if it were String^
gcroot<String^> str;
CppClass() {}
};
int main()
{
CppClass cobj;
// using the gcnew...
cobj.str = gcnew String("Hello dude!!!");
// no cast required
Console::WriteLine("cobj.str = {0}", cobj.str);
return 0;
}
Output:

The following working program example shows how to create a gcroot object on the native heap.
// gcroot keyword
// compile with: /clr
#include "stdafx.h"
#include <vcclr.h>
using namespace System;
// native C++ struct...
struct CppClass
{
gcroot<String ^> * str;
// the new and
CppClass() : str(new gcroot<String ^>) {}
// delete keywords, destructor...
~CppClass() {delete str;}
};
int main()
{
CppClass cobj;
// using the gcnew...
*cobj.str = gcnew String("hello cutie!!!");
Console::WriteLine("*cobj.str = {0}", *cobj.str);
return 0;
}
Output:

The following sample code shows how to gcroot to hold references to value types (not reference types) in a native type by using gcroot on the boxed type.
// gcroot keyword
// compile with: /clr
#include "stdafx.h"
#include <vcclr.h>
using namespace System;
public value struct Vstruct
{
String^ str;
};
class Native
{
public:
gcroot< Vstruct^ > v_handle;
};
int main()
{
Native nativecls;
Vstruct vobj;
nativecls.v_handle = vobj;
nativecls.v_handle->str = "Hello world!!!";
Console::WriteLine("String in Vstruct: {0}", nativecls.v_handle->str);
return 0;
}
Output:
