Proper Object Disposal In C++/CLI

自古美人都是妖i 提交于 2019-12-24 10:00:18

问题


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?


回答1:


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 Workspace is constructed, which may save you a lot of gcnew stuff in your hand-written constructor.

That is, if you say:

Form WorkspaceUI;

Then you don't need to say:

WorkspaceUI = gcnew Form();

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:

Form.Controls->Add(WorkspaceSplitter);

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:

ref class Fred { };

// function that accepts a handle
void ping(Fred ^h) { }

// Elsewhere... declare object of type Fred
Fred f;

// Get handle to pass to function
ping(%f);

If repeatedly creating and deleting objects of your class leads to out-of-memory there are two possibilities:

  • You are inadvertently holding references to it (or something it allocates). See my answer to this question: Memory Leaks in C# WPF (it doesn't have anything specific to do with C# or WPF really, it's just a matter of using the debugger interactively)
  • You need to call Dispose on 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 Dispose automatically - 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 Dispose on 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 Dispose method), it will automatically call Dispose on any member objects that require it.



来源:https://stackoverflow.com/questions/7858389/proper-object-disposal-in-c-cli

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!