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

C++ dynamic loading of classes: Why is a "destroy" function needed?

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

我明白为什么需要 "create" 函数,但为什么需要 "destroy" 函数?为什么不将接口析构函数声明为纯虚函数?

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

~polygon() = 0;

triangle 的析构函数是:

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

然后当我使用:

delete poly;

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

我试图寻找其他示例,但他们都提到并使用了 "destroy" 函数,没有使用简单的纯虚拟析构函数的示例,这让人相信我在这里遗漏了一些东西,所以..什么是吗?

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

进一步阅读the same link

You must provide both a creation and a destruction function; you must not destroy the instances using delete from inside the executable, but always pass it back to the module. This is due to the fact that in C++ the operators new and delete may be overloaded; this would cause a non-matching new and delete to be called, which could cause anything from nothing to memory leaks and segmentation faults. The same is true if different standard libraries are used to link the module and the executable.

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

在任何情况下,shared_ptr 都可以通过调用自定义删除器的 lambda 函数相当轻松地获得自定义删除器;是的,shared_ptr 不能在其模板参数中包含删除器,这有点烦人,但是您可以编写一个简单的包装器,使其 simpler/less 冗长,以在所有位置使用一致的删除器创建它(不编译器现在可用,请原谅任何拼写错误):

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

如果您真的想按照链接到的示例进行操作,可以使用自定义函数,以便在智能指针应删除其对象时使用。

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

用这个而不是 delete 当共享指针应该删除自身时,将调用 lambda。

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

The background of not wanting to use a destroy function is that I want to use the allocated object in a shared_ptr and not care later about its lifetime, working with a "destroy" function will be tricky, therefore I need to know if it's necessary.

然后您将需要 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");