C ++动态加载类:为什么需要“destroy”函数?

时间:2016-10-18 13:05:49

标签: c++ memory-management dlopen dynamic-loading

This page检查并给出了一个非常明确的示例,说明如何动态加载和使用类,但有些事情我很难理解:

我理解为什么需要“创建”功能,但为什么需要“破坏”功能呢?为什么不将界面析构函数声明为纯虚拟?

我做了一个相同的例子,除了:

~polygon() = 0;

triangle的析构函数是:

triangle::~triangle() {
    std::cout << "triangle Dtor is called" <<std::endl;
}

然后当我使用:

delete poly;

确实显示了该消息(Linux下的GCC 5.4.0)。

我试图寻找其他的例子,但他们都提到并使用了“破坏”功能,没有使用简单的纯虚拟析构函数的例子,这让我相信我在这里缺少一些东西,所以......它是什么? / p>

不想使用destroy函数的背景是我想在shared_ptr中使用已分配的对象而不关心它的生命周期,使用“destroy”函数将是棘手的,因此我需要知道是否有必要。

3 个答案:

答案 0 :(得分:3)

the same link中进一步阅读:

  

您必须同时提供创建和销毁功能;您不能使用可执行文件内的删除来销毁实例,但始终将其传递回模块。这是因为在C ++中,运算符new和delete可能会重载;这将导致调用不匹配的new和delete,这可能导致任何内容泄漏和分段错误。如果使用不同的标准库来链接模块和可执行文件,情况也是如此。

这里的关键字是new and delete may be overloaded,因此在调用者的代码中执行的操作与在共享对象的代码中执行的操作不同,如果在二进制文件中使用delete,它将调用析构函数并且它将根据共享对象中的析构函数释放内存,但这可能不是共享对象中delete操作符的行为,共享对象中的new可能没有分配任何内存,因此您将拥有可能的分段错误,也许new正在做的事情不仅仅是为该对象分配内存而且通过不调用共享对象中的匹配delete存在泄漏,也有可能存在不同的堆共享对象和二进制文件之间的处理。

在任何情况下shared_ptr都可以使用调用自定义删除器的lambda函数轻松地为自定义删除器提供;是的,shared_ptr不能在其模板参数中包含删除器,这有点令人讨厌,但您可以编写一个简单的包装器,使其更简单/更简洁,在所有位置使用一致的删除器创建它(没有可用的编译器)现在,原谅任何错别字):

shared_ptr<triangle> make_shared_triangle(triangle *t) {
    return std::shared_ptr<triangle>(t, [](triangle *t) { destroy_triangle(t); });
}

答案 1 :(得分:2)

如果您真的想通过链接的示例,可以使用自定义函数,当智能指针删除它的对象时。

std::shared_ptr<class> object(create_object(), //create pointer
[=](class* ptr)
{
    destroy_object(ptr);
});

使用此代替delete,当共享指针应自行删除时,将调用lambda。

注意:我将函数指针复制到lambda中的destroy_object函数([=]将执行此操作)。只要在动态加载的上下文中使用它时不调用dlclose(),这应该是有效的。当您使用dlclose时,这会导致错误。

答案 2 :(得分:0)

  

不想使用destroy函数的背景是我想在shared_ptr中使用已分配的对象而不关心它的生命周期,使用“destroy”函数会很棘手,因此我需要知道是否这是必要的。

然后,您需要create your shared_ptr使用显式Deleter(请参阅构造函数的表单4。向下滚动到示例)。

template< class Y, class Deleter > shared_ptr( Y* ptr, Deleter d );

类似的东西:

shared_ptr<polygon> sh_ptr_val(
                     my_triangle, 
                     [](auto ptr) { destroy_triangle(ptr); }
                   );

[编辑以解决Hayt的第一条评论]

struct triangle_factory { 
  static shared_ptr<triangle> create() {
    shared_ptr<polygon> ret(
                         create_triangle(), 
                         [](auto ptr) { destroy_triangle(ptr); }
                       );
    return std::move( ret )
  }; 
private: 
   static create_t* create_triangle; 
   static destroy_t* destroy_triangle; 
}

create_t* triangle_factory::create_triangle=(create_t*) dlsym(triangle, "create");
destroy_t* triangle_factory::destroy_triangle=(destroy_t*) dlsym(triangle, "destroy");