Joh*_*nes 2 c++ virtual-functions dynamic-linking
例如,此代码段错误(请参阅main.cpp中的注释).
hello.h
struct A { virtual ~A() {} };
HELLO.CPP
#include "hello.h"
extern "C" {
    void hello(A*& a) {
        a = new A;
    }
}
main.cpp中:
#include <cassert>
#include <dlfcn.h>
#include "hello.h"
int main() {
    void* handle = dlopen("./hello.so", RTLD_LAZY);
    assert(handle);
    typedef void (*hello_t)(A*& a);
    hello_t hello = (hello_t) dlsym(handle, "hello");
    assert(hello);
    A* a = nullptr;
    hello(a);
    dlclose(handle);
    delete a; // -> segfault
}
编
g++ -Wall -std=c++11 -g main.cpp -ldl -o main
g++ -Wall -std=c++11 -g -shared -fpic hello.cpp -o hello.so
原因:A包含一个虚拟表.在a分配时,虚拟表包含指向函数段的指针hello.so.调用之后dlclose(),此函数段可能无效,导致指针无效,因此delete a调用函数内存不足.
到目前为止这么清楚.我的问题是,所有假设您dlclose()的库,然后继续使用对象:
std::string保证在没有虚拟析构函数的情况下实现,谁知道它是否包含一个内部对象?动态链接库没有问题.它们并不危险.
但是,您正在演示卸载动态加载的库的问题.您无法卸载库,然后继续使用对该库中数据的引用:数据指针,函数指针,虚函数等.就像在你之后使用指针一样delete:唯一的答案就是在delete你完成对象之前避免调用.
因此,使用动态加载的库dlopen()并且和... dlclose()一样危险......没有什么可以阻止你做错事,你必须知道如何正确使用这些功能.newdelete
在典型的使用中(没有动态加载),动态链接库将在程序执行的整个持续时间内保持驻留状态.因此,如果std::string在动态库中,其功能将始终可用.就像一个静态库.
析构函数是虚拟的这一事实在这里并不真正相关,因为不涉及继承。问题很简单,您在关闭库后调用了库中实现的函数(析构函数)。直接调用非虚成员函数也会导致同样的问题,因为该函数的代码在库中并且库已被卸载。
只需保持库打开,直到使用完它实现的对象为止。
您的分析不正确.问题不在于dlclose(handle)析构函数的代码不再存在,这意味着您的代码崩溃了.保持库打开,可以调用析构函数.
但是,在某些情况下,您还会为每个共享库获取不同的堆,因此最好在共享库中保留动态分配对象的构造和销毁.您可以通过第二个函数实现这一目标bye(),做delete你的对象.
通常情况下"动态添加内容"的问题(你的例子中的a std::string不是很好,因为实现应该只分配char元素,但是std::vector在复制元素时可能会分配东西)通过将它封装在对象中来处理分配由共享库中的代码完成.
(您的分析中的细节也是错误的:vtable本身不存储在堆上,但指向它的vptr必须存储在对象中,在这种情况下,它在堆上)
| 归档时间: | 
 | 
| 查看次数: | 1363 次 | 
| 最近记录: |