我知道我可以在共享库中实现类的一部分,只要在使用时加载符号。
myclass.h
---
class C {
void method();
}
main.cpp
---
#include "myclass.h"
int main() {
//dynamically load mylib.so using dlopen/dlsym/dlclose
...
C *c = new C();
c->method();
delete c;
}
mylib.so compiled separately:
====
mylib.cpp
---
#include "mylib.h"
void C::method() {
...
}
这很好用。
然而,一旦我完成了使用C :: method(),我想卸载它,所以我可以更改,重新编译并重新加载它而无需重新启动主程序
int main() {
//dynamically load mylib.so using dlopen/dlsym/dlclose
...
C *c = new C();
c->method();
delete c;
// close the lib, remove the handle...
....
char pause;
cin << pause; // before carrying on change the C::method, recompile it
//dynamically load *Again* mylib.so using dlopen/dlsym/dlclose
...
C *c = new C();
c->method();
delete c;
}
问题是它在执行第一个dlclose时没有卸载库,可能是因为我的类C的实例存在。 有什么方法可以强迫这个吗?
(在Linux Ubuntu 10.04上使用g ++ 4.2.3)
答案 0 :(得分:10)
它不会像你这样做。你的方法可能还有其他问题,但还没有让你感到困惑。
程序/库中的未定义符号会在不同时间解析。在大多数系统上,加载程序/库时始终会解析数据引用(全局变量,类vtable等)。首次在某些系统上使用代码引用时会解析(“延迟查找”;至少在Linux和Mac OS X上发生),除非设置了一些特殊选项(dlopen或LD_BIND_NOW环境变量的RTLD_NOW参数)。一旦解决了这些问题,就不会进行新的查找。
如果在完成方法的延迟查找之前dlopen
具有RTLD_GLOBAL标志的库,则将使用库中的方法。现在解决了该方法的代码引用;它不会再改变。您的主程序现在正式使用dlopen
ed库中的符号,因此dlclose
将不再关闭库 - dlclose
只会删除您的显式句柄。
简而言之,您应该只希望卸载只能通过显式调用dlsym
来使用的库。
您可以做的是让您的库提供派生类实现。您将类C
定义为抽象基类:
class C
{
public:
virtual void method();
};
在单独编译的库中,您将定义派生类和创建该派生类的对象的函数:
class D : public C
{
public:
virtual void method();
};
void D::method()
{
// ...
}
extern "C" C* createC()
{
return new D();
}
现在,在您的主程序中,您将使用dlopen
加载库,使用createD
获取指向dlsym
的函数指针并调用它来获取对象。当所有对象都消失后,你可以调用dlclose
,重新编译你的库,然后再做一遍:
typedef C* (*creatorFunction)();
int main()
{
for(;;)
{
void *handle = dlopen("mylib.so", 0);
creatorFunction create = (creatorFunction) dlsym(handle, "createC");
C *c = (*create)();
c->method();
delete c;
dlclose(handle);
char pause;
cin << pause;
}
return 0;
}
答案 1 :(得分:-1)
感谢帮助人员,只是通知:
别忘了在C类中将方法初始化为零(此类不在共享库中),并将虚拟销毁器设置为默认值
如果您想知道dlopen的标志是0->它是RTLD_LOCAL