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

Mys*_*din 4 c++ memory-management dynamic-loading dlopen

这一页检查并给出了如何动态加载和使用类的非常清晰的示例,但有一些我很难理解的内容:

我明白为什么需要“创建”功能,但为什么需要“销毁”功能?为什么没有将接口析构函数声明为纯虚拟函数?

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

~polygon() = 0;
Run Code Online (Sandbox Code Playgroud)

的析构函数triangle是:

triangle::~triangle() {
    std::cout << "triangle Dtor is called" <<std::endl;
}
Run Code Online (Sandbox Code Playgroud)

然后当我使用时:

delete poly;
Run Code Online (Sandbox Code Playgroud)

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

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

不想使用销毁函数的背景是我想在 a 中使用分配的对象shared_ptr并且以后不关心它的生命周期,使用“销毁”函数会很棘手,因此我需要知道是否有必要。

Sha*_*ger 5

在同一链接中进一步阅读:

您必须提供创建和销毁函数;您不得使用可执行文件内部的删除来销毁实例,而始终将其传递回模块。这是因为在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); });
}
Run Code Online (Sandbox Code Playgroud)

  • @MysticOdin:所描述的场景是可执行文件显式动态加载函数来创建(和销毁)它没有实现的对象,该对象可能有不同的“删除”。考虑一个具有一对“new”/“delete”的二进制文件,以及一个与另一对共享的对象(我们将其称为“newweird”/“deleteweird”)。SO 中的工厂函数调用“newweird”。如果你只是让二进制调用“delete”中的“shared_ptr”,它就不会使用“deleteweird”;你有一个不匹配的情况(用“newweird”分配,用“delete”删除),这可能会损坏堆或程序出现段错误。 (2认同)