Consider the following class:
public ref class Workspace
{
protected:
Form^ WorkspaceUI;
SplitContainer^ WorkspaceSplitter;
AvalonEditTextEditor^ TextEditor;
ScriptOffsetViewer^ OffsetViewer;
SimpleTextViewer^ PreprocessedTextViewer;
ListView^ MessageList;
ListView^ FindList;
ListView^ BookmarkList;
ListView^ VariableIndexList;
TextBox^ VariableIndexEditBox;
Label^ SpoilerText;
ToolStrip^ WorkspaceMainToolBar;
ToolStripButton^ ToolBarNewScript;
ToolStripButton^ ToolBarOpenScript;
ToolStripButton^ ToolBarPreviousScript;
ToolStripButton^ ToolBarNextScript;
ToolStripSplitButton^ ToolBarSaveScript;
ToolStripDropDown^ ToolBarSaveScriptDropDown;
ToolStripButton^ ToolBarSaveScriptNoCompile;
ToolStripButton^ ToolBarSaveScriptAndPlugin;
ToolStripButton^ ToolBarRecompileScripts;
ToolStripButton^ ToolBarCompileDependencies;
ToolStripButton^ ToolBarDeleteScript;
ToolStripButton^ ToolBarNavigationBack;
ToolStripButton^ ToolBarNavigationForward;
ToolStripButton^ ToolBarSaveAll;
ToolStripButton^ ToolBarOptions;
ArbitraryCustomClass^ CustomClassInstance;
public:
Workspace()
{
WorkspaceUI = gcnew Form();
WorkspaceSplitter = gcnew SplitContainer();
// ...
Form->Controls->Add(WorkspaceSplitter);
// ...
WorkspaceUI->Show();
}
~Workspace
{
// dispose stuff here
}
};
What would be the most efficient and elegant way to dispose an instance of the above class so that all of its memory is reclaimed by the GC during its next collection? Do I need to call delete explicitly on each member and/or reset them to nullptr?
NB. You may not need to do anything. Memory for objects is reclaimed by the GC when references no longer exist that point to it.
You only need to explicitly reclaim when an object implements
IDisposable. In C++/CLI this maps to destructors.So if none of the objects you’re allocating need to be disposed, you can ignore the rest of this answer. But supposing they do…
Remove the
^from each field and they will be reclaimed automatically.It would also mean that they would be default-constructed automatically when the
Workspaceis constructed, which may save you a lot ofgcnewstuff in your hand-written constructor.That is, if you say:
Then you don’t need to say:
The compiler has already generated that for you – imagine it being inserted at the start of your constructor.
Nor do you need to dispose/delete anything.
Finally, you need to use
.instead of->to access members of the objects that you declare in this way:Update:
In C++/CLI, handles to ref classes are declared with
^, and this is analogous to the way pointers to native classes are declared with*.Also correspondingly, there needs to be a way to get a handle to an object. To get a pointer to a native object, we prefix with
&. To get a handle to a ref object, we prefix with%. For example:If repeatedly creating and deleting objects of your class leads to out-of-memory there are two possibilities:
Disposeon one or more of the objects you allocate inside your class.If it’s the latter, in C++/CLI there is built-in support for calling
Disposeautomatically – C++/CLI treats a disposable object as if it was a C++ ref class with a destructor.So if you delete a handle, you’re calling
Disposeon the object it points to.Or if (as I suggest above) you simply have member objects, you don’t even need to explicitly delete. When the outer containing class is destructed (i.e. something calls its
Disposemethod), it will automatically callDisposeon any member objects that require it.