Является ли пользовательское средство удаления для 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
оператор, но вы все равно должны уничтожить объект, таким образом, вы должны вызвать деструктор объекта.