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

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

本文关键字:destroy 函数 为什么 动态 加载 C++      更新时间:2023-10-16

这个页面检查并给出了一个关于如何动态加载和使用类的非常清晰的例子,但是有一些东西我很难理解:

我理解为什么需要"创建"函数,但为什么需要"销毁"函数?为什么将接口析构函数声明为纯虚函数还不够?

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

~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"函数将是棘手的,因此我需要知道它是否必要。

在同一链接中继续阅读:

必须同时提供创建函数和销毁函数;您不能在可执行文件中使用delete来销毁实例,而是始终将其传递回模块。这是因为在c++中,new和delete操作符可能被重载;这将导致调用不匹配的new和delete,从而可能导致从什么都没有到内存泄漏和分段错误等各种问题。如果使用不同的标准库来链接模块和可执行文件,则也是如此。

这里的关键字是new and delete may be overloaded因此做些不同的调用者的代码比共享对象的代码,如果您使用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); });
}

如果你真的想按照你链接到的例子去做,你可以使用一个自定义函数,当智能指针应该删除它的对象时使用。

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

用这个代替delete,当共享指针应该删除自己时将调用lambda。

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

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

然后,您需要使用显式的Deleter创建shared_ptr(参见构造函数的形式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); }
                   );

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");