I'm using this class:
public ref class x: public System::Windows::Forms::Form
{
private: gcroot<std::string> name;
}
and i am getting the following error:
IntelliSense: a member of a managed class cannot be of a non-managed class type
I know i can use char*
, but if I use lots of char*
i will have to manually do the delete[]
or some heap corruption issues will rise
I've been stuck on this for two days now
note: I have to use c++ and have to use UI in c++
If you embed an unmanaged class within a managed class you'll need to 'pin' it because the garbage collector might actually 'compact' during execution of the managed class, essentially moving the actual address of the unmanaged class in the heap which can cause huge problems. So use the
__pin
keyword when initializing your managed class that contains any unmanaged references.gcroot
is used for another purpose: to keep CLR class member in a native class. You need to keep native class member in CLR class. This is not allowed directly as well, but you can keep pointer to native class as a member:Initialize
name
tonew string("...");
in the class constructor or in another place where this is necessary, and use it. To prevent memory leak, releasename
in the class finalizer and destructor.Notes:
Avoid using mixed types if this is not absolutely necessary. For example, in this case you can use pure CLR
String^
instead of nativestd::string
.To write native C++ with GUI it is much better to use some native UI framework: Win32 API, MFC, Qt etc. Using Windows Forms GUI in C++/CLI is very difficult way - you need to know well both C++ and .NET. In any case, C++/CLI Windows Forms application type is abandoned in newest Visual Studio versions. Reconsider your approach.
That's the wrong usage for gcroot<>, you only need that if you keep a reference to a managed object in an unmanaged class.
In this case you only need to declare it
string*
. A pointer, you cannot store an string object inside your managed class, the compiler is convinced that you are going to shoot your leg off. You'll get the exact same error message you got now.Really Bad Things can happen when the garbage collector compacts the gc heap and moves the Form object. That invalidates any external unmanaged pointer to the string object without the garbage collector being able to update that pointer. Such a pointer can for example be generated when you pass a reference to the string to unmanaged code and the GC happens while that unmanaged code is executing. The pointer is now no longer valid and the unmanaged code fails when it reads garbage or corrupts the GC heap. Especially the latter mishap is extremely hard to diagnose. Just calling one of the std::string member methods is enough to invoke this failure mode, that generates the this pointer.
It is very unusual to actually need an std::string in a managed object, you always choose
String^
first. And generate the std::string only when needed, typically when you call native code. Only ever consider doing it your way if creating the std::string on-the-fly is exceedingly expensive. If you do then create the std::string object in the constructor. And destroy it again in both the destructor and the finalizer. Which is pretty tricky to get right for the Form class since it already has a destructor and finalizer, strongly consider creating a little helper class that stores the string.