【问题标题】:Is custom deleter for std::unique_ptr a valid place for manual call to destructor?std::unique_ptr 的自定义删除器是手动调用析构函数的有效位置吗?
【发布时间】: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-&gt;~Plugin();..但这就是我要问的,真的..
  • @SebastianRedl Plugin::CreateInstance 是唯一知道要实例化什么类的地方。 Plugin 是整个类层次结构的基类,所有类都有对应的Type。所以如果你有一个Type对象,并在它上面调用CreateInstance(),就会调用对应类的静态CreateInstance来实例化正确的类型。

标签: c++ c++11 destructor unique-ptr incomplete-type


【解决方案1】:

std::unique_ptr 的删除器应该删除对象,也就是说销毁它(你可以假设它应该是这样),然后根据需要释放使用的内存。

如果您的自定义删除器使用delete 运算符,那么您不必手动调用析构函数:

delete 是一个具有非常特殊行为的运算符:一个表达式 使用 delete 运算符,首先调用适当的析构函数(对于 类类型),然后调用函数运算符delete(即this 函数)释放存储。

如果您使用静态分配的内存或在静态分配的内存中创建指针或在应用程序退出之前不会释放的内存(例如),那么您不应调用 delete 运算符,而是您仍然需要销毁对象,因此您必须调用对象的析构函数。

【讨论】:

  • 我想我现在明白了 :)
猜你喜欢
  • 2013-03-30
  • 2018-01-02
  • 2015-08-15
  • 2018-01-31
  • 2015-12-20
  • 1970-01-01
  • 1970-01-01
  • 2012-04-11
  • 2016-03-31
相关资源
最近更新 更多