Является ли пользовательское средство удаления для std::unique_ptr допустимым местом для ручного вызова деструктора?

У меня есть очень базовая реализация отражения, которая включает в себя Type класс, который создает объект для класса, который он описывает. Разобравшись до соответствующих частей, это выглядит так:

Type.h:

class Plugin; // forward declaration

typedef std::unique_ptr<Plugin> PluginPtr;

namespace Reflection {

    class Type {
    public:
        explicit Type(PluginPtr(*)());
        PluginPtr CreateInstance();
    private:
        PluginPtr(*_createInstance_Handler)();
    };

}

Type.cpp:

Type::Type(PluginPtr(*createInstance_Handler)()) :
    _createInstance_Handler(createInstance_Handler) {}

PluginPtr CreateInstance() { return (*_createInstance_Handler)(); }

Фактическая логика создания находится в Plugin класс (а также у каждого из его потомков):

Plugin.h:

class Plugin {
public:
    virtual ~Plugin();
    static const Reflection::Type Type;
private:
    static PluginPtr CreateInstance();

plugin.cpp

Plugin::~Plugin() {}

const Reflection::Type Plugin::Type(CreateInstance);

PluginPtr Plugin::CreateInstance() { return PluginPtr(new Plugin); }

Когда я пытаюсь скомпилировать это, я получаю следующие ошибки (в Visual Studio 2013):

error C2027: use of undefined type 'Plugin'
error C2338: can't delete an incomplete type
warning C4150: deletion of pointer to incomplete type 'Plugin'; no destructor called

Я немного покопался, и, очевидно, это вызвано удалением std::unique_ptr (оказавшимся внутри определения класса, над которым он работает). Я где-то читал, что если я добавлю свой собственный средство удаления, эта проблема исчезнет. Поэтому я переопределил PluginPtr к этому:

typedef std::unique_ptr<Plugin, PluginDeleter> PluginPtr

Проблема (компиляции) действительно исчезает, но тогда возникает вопрос: можно ли это сделать? PluginDeleter вызов ~Plugin() вручную (чтобы убедиться, что плагин (и любой производный объект, на который может указывать PluginPtr!) был должным образом уничтожен)? И где / как мне лучше всего объявить / определить его, чтобы у меня не возникало той же проблемы с неполными типами?

(или есть лучший способ вообще?)

PS. Работая над моим исходным кодом, я понимаю, что в приведенном выше коде есть ошибка. Последняя строка в Type.cpp должна читаться

    PluginPtr CreateInstance() { return (_createInstance_Handler)(); }

1 ответ

Решение

Удалитель std::unique_ptr следует удалить объект, то есть уничтожить его (как можно предположить), а затем освободить используемую память, если это необходимо.

Если ваш пользовательский инструмент удаления использует delete оператор, то вам не нужно вручную вызывать деструктор как:

delete является оператором с очень специфическим поведением: выражение с оператором удаления сначала вызывает соответствующий деструктор (для типов классов), а затем вызывает оператор функции delete (т.е. эта функция), чтобы освободить хранилище.

Если вы создаете указатель, используя статически выделенную память или новое место размещения в статически выделенной памяти или память, которую вы не освободите до завершения работы приложения (например), то вам не следует вызывать delete оператор, но вы все равно должны уничтожить объект, таким образом, вы должны вызвать деструктор объекта.

Другие вопросы по тегам