Правильное удаление объектов в C ++ / CLI - PullRequest
1 голос
/ 22 октября 2011

Рассмотрим следующий класс:

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 ?

1 Ответ

5 голосов
/ 22 октября 2011

NB. Возможно, вам не нужно ничего делать. Память для объектов восстанавливается ГХ, когда ссылки на нее больше не существуют.

Вам необходимо явно восстановить, только когда объект реализует 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);

Если многократное создание и удаление объектов вашего класса приводит к нехватке памяти, есть две возможности:

  • Вы случайно держите ссылки на него (или что-то, что он выделяет). См. Мой ответ на этот вопрос: Утечки памяти в C # WPF (на самом деле он не имеет ничего общего с C # или WPF, это просто вопрос интерактивного использования отладчика)
  • Вам нужно вызвать Dispose для одного или нескольких объектов, которые вы выделяете внутри своего класса.

Если это последнее, в C ++ / CLI есть встроенная поддержка автоматического вызова Dispose - C ++ / CLI обрабатывает одноразовый объект, как если бы это был класс C ++ ref с деструктором.

Таким образом, если вы удаляете дескриптор, вы вызываете Dispose для объекта, на который он указывает.

Или если (как я предлагаю выше) у вас просто есть объекты-члены, вам даже не нужно явно удалять. Когда внешний содержащий класс уничтожается (то есть что-то вызывает его метод Dispose), он автоматически вызывает Dispose для любых объектов-членов, которым это требуется.

...