C ++:在分离的共享库中实现类方法

问题描述 投票:7回答:2

我想我可以在共享库中实现类的一部分,只要在使用时加载符号。

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)

c++ class implementation dlopen
2个回答
10
投票

Short Answer

它不会像你那样工作。你的方法可能还有其他问题,但还没有让你感到困惑。

Why it doesn't work

程序/库中未定义的符号将在不同时间解析。在大多数系统上,加载程序/库时始终会解析数据引用(全局变量,类vtable等)。首次在某些系统上使用代码引用时会解析(“延迟查找”;至少在Linux和Mac OS X上发生),除非设置了一些特殊选项(dlopen或LD_BIND_NOW环境变量的RTLD_NOW参数)。一旦解决了这些问题,就不会进行新的查找。

如果在完成方法的延迟查找之前,使用RTLD_GLOBAL标志对库进行dlopen,则将使用库中的方法。现在解决了该方法的代码引用;它不会再改变。您的主程序现在正式使用来自dlopened库的符号,因此dlclose将不再关闭库 - dlclose只会删除它的显式句柄。

简而言之,您应该只希望卸载只能通过显式调用dlsym使用的库。

What to do instead

你可以做的是让你的库提供派生类实现。您将类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
投票

谢谢你的帮助,只是一个通知:

不要忘记在C类中将方法初始化为零(此类不在共享库中),并将虚拟驱逐舰设置为默认值

如果你想知道dlopen的标志是0 - >它是RTLD_LOCAL

© www.soinside.com 2019 - 2024. All rights reserved.