C ++ / CLI中的正确对象处置 [英] Proper Object Disposal In C++/CLI

查看:241
本文介绍了C ++ / CLI中的正确对象处置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下类:

  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
{
//在这里处理
}
};

什么是最有效率和优雅的方式来处理上述类的实例,它的内存在GC的下一个收集过程中被回收?是否需要在每个成员上明确调用 delete 和/或将它们重置为 nullptr

解决方案

注意。。您可能不需要执行任何操作。



当对象实现 IDisposable时,只需显式回收。在C ++ / CLI中,它映射到析构函数。



因此,如果没有要分配的对象需要处理,则可以忽略此答案的其余部分。但是假设他们... ...



从每个字段中删除 ^ ,他们将被自动回收。 p>

这也意味着当 Workspace 构建时,它们将是默认构造的,这可以节省很多



也就是说,如果你说:

$ gcnew b
$ b

 表单WorkspaceUI; 

那么你不需要说:

  WorkspaceUI = gcnew Form(); 

编译器已经为你生成了 - 想象它被插入到构造函数的开头。 / p>

也不需要处理/删除任何内容。



最后,您需要使用而不是 - > 访问您以这种方式声明的对象的成员:

  Form.Controls-> Add(WorkspaceSplitter); 

更新



在C ++ / CLI中,ref类的句柄用 ^ 声明,这类似于使用 *



也相应地,需要一种方法来获取对象的句柄。要获得指向本地对象的指针,我们用& 作为前缀。要获取ref对象的句柄,我们用作为前缀。例如:

  ref class Fred {}; 

//接受句柄的函数
void ping(Fred ^ h){}

//其他...声明对象类型Fred
Fred f;

//获取传递给函数的句柄
ping(%f);

如果重复创建和删除类的对象导致内存不足,




  • 您不经意地持有对它的引用(或它分配的内容)。请参阅我对此问题的回答: C#WPF中的内存泄漏 (它没有任何与C#或WPF真正的关系,这只是一个交互使用调试器的问题)

  • 您需要调用 Dispose 对您在类中分配的一个或多个对象。



如果是后者,在C ++ / CLI有自动调用 Dispose 的内置支持 - C ++ / CLI将一次性对象视为一个带析构函数的C ++ ref类。



所以如果你删除一个句柄,你在它指向的对象上调用 Dispose



或者如果(如上面建议的)你只有成员对象,你甚至不需要显式删除。当外部包含类被破坏(即某事调用其 Dispose 方法)时,它会自动调用 Dispose 需要它的对象。


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 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.

这篇关于C ++ / CLI中的正确对象处置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆