【发布时间】:2014-02-02 08:56:10
【问题描述】:
我有一个非常基本的反射实现,其中包括一个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)();
};
}
类型.cpp:
Type::Type(PluginPtr(*createInstance_Handler)()) :
_createInstance_Handler(createInstance_Handler) {}
PluginPtr CreateInstance() { return (*_createInstance_Handler)(); }
实际的实例化逻辑位于Plugin 类中(以及它的每个后代):
插件.h:
class Plugin {
public:
virtual ~Plugin();
static const Reflection::Type Type;
private:
static PluginPtr CreateInstance();
插件.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)(); }
【问题讨论】:
-
use of undefined type 'Plugin': 你之前试过用完整类型吗?即在使用它的 unique_ptr 之前声明整个类? -
您在 PluginDeleter 中使用
delete吗? -
自定义删除器不是必需的,也不会真正有帮助。您只需要确保在销毁 PluginPtr 的任何地方都有可用的
Plugin的完整定义(包括Plugin.h)。附带说明一下,我看不出静态Plugin::CreateInstance有什么意义。 -
我还没有真正在其中做任何事情,因为我不确定该做什么。我已经草绘了一个看起来像这样的:
struct PluginDeleter { void operator()(Plugin*); },在定义Plugin类之后的某个地方定义了这样做:plugin->~Plugin();..但这就是我要问的,真的.. -
@SebastianRedl
Plugin::CreateInstance是唯一知道要实例化什么类的地方。Plugin是整个类层次结构的基类,所有类都有对应的Type。所以如果你有一个Type对象,并在它上面调用CreateInstance(),就会调用对应类的静态CreateInstance来实例化正确的类型。
标签: c++ c++11 destructor unique-ptr incomplete-type