1

考慮下面的類:正確的對象處理在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 
    { 
     // dispose stuff here 
    } 
}; 

什麼是最有效和最優雅的方式來處理上述類的實例,使所有的內存是由GC回收在下一次收集?我是否需要撥打刪除明確在每個成員和/或重置他們到nullptr

回答

5

NB。你可能不需要做任何事情。當引用不再存在時指向該對象的內存將由GC回收。

只有當對象實現IDisposable時,您才需要明確回收。在C++/CLI中,它映射到析構函數。

因此,如果您分配的對象都不需要處理,您可以忽略此答案的其餘部分。但假設他們做...

從每個字段中刪除^,他們將自動收回。

這也意味着它們將在構建Workspace時自動默認構建,這可以爲您在手寫構造函數中節省大量gcnew材料。

也就是說,如果你說:

Form WorkspaceUI; 

那麼你也沒必要說:

WorkspaceUI = gcnew Form(); 

編譯器已經生成了你 - 想象它被插入在開始你的構造函數。

你也不需要處置/刪除任何東西。

最後,你需要使用.,而不是->訪問您以這種方式申報的對象的成員:

Form.Controls->Add(WorkspaceSplitter); 

更新:

在C++/CLI,句柄REF類聲明爲^,這類似於用*聲明本地類的指針。

也相應地,需要一種方法來獲取對象的句柄。要獲得指向本地對象的指針,我們以&作爲前綴。爲了得到一個ref對象的句柄,我們在前綴%。例如:

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); 

如果反覆創建和刪除您的類的對象導致了內存不足的有兩種可能性:

  • 您無意中持有對它的引用(或東西它分配) 。看到我對這個問題的回答:Memory Leaks in C# WPF(它沒有任何特定的與C#或WPF有關的事情,它只是交互式地使用調試器的問題)
  • 您需要致電Dispose關於一個或多個對象分配給你的班級。

如果是後者,在C++/CLI有內置的支持用於自動調用Dispose - C++/CLI治療的一次性對象,如果它是一個C++引用類與析構函數。

所以,如果你刪除一個句柄,你就在它指向的對象上調用Dispose

或者如果(如我上面所建議的)你只是有成員對象,你甚至不需要顯式刪除。當外層包含類被破壞時(即某些方法調用其方法Dispose),它將自動在需要它的任何成員對象上調用Dispose

+0

在這種情況下,如何將對象傳遞給需要其句柄的函數?如: Label SomeText; Form.Controls-> Add(SomeText); //引發編譯器錯誤 – shadeMe

+0

此外,繼續創建和銷燬上述類只會導致System.OutOfMemoryException - GC似乎不會回收對象的內存。這使我相信,它可能有強烈的參考甚至過去的破壞。在我的代碼中,所有類的實例都被分配並直接添加到列表中。銷燬時,實例將從相同的位置移除。這是每個實例在根中獲取的唯一參考。然而,這個班的不同成員有多個內部參考。 – shadeMe

+0

@shadeMe:您需要在Workspace對象本身調用Dispose來觸發處理所有擁有的對象。 –