C ++:在分离的共享库中实现类方法 [英] C++: implementation of a class methods in a separated shared library

查看:166
本文介绍了C ++:在分离的共享库中实现类方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

 

我想知道在共享库中实现一个类的部分, code> myclass.h
---

class C {
void method();
}

main.cpp
---

#includemyclass.h
int main(){
//动态加载mylib.so使用dlopen / dlsym / dlclose
...
C * c = new C();
c-> method();
delete c;
}

mylib.so单独编译:
====
mylib.cpp
---

# includemylib.h
void C :: method(){
...
}

这很好。



但是一旦我使用C :: method(),我想卸载它,更改,重新编译并重新加载而不必重新启动主程序

  int main(){
//动态加载mylib.so使用dlopen / dlsym / dlclose
...
C * c = new C();
c-> method();
delete c;
//关闭lib,删除句柄...
....
char pause;
cin<<暂停; //在改变C ::方法之前,重新编译它

//动态加载*再次* mylib.so使用dlopen / dlsym / dlclose
...
C * c = new C();
c-> method();
delete c;
}

问题是当做第一个dlclose时,可能是因为我的类C的一个实例存在。
任何方式强制这样做?



(在Linux Ubuntu 10.04上使用g ++ 4.2.3)

解决方案

短回答



它不会像你这样做。



为什么不起作用



程序/库中未定义的符号在不同时间解析。在大多数系统上,加载程序/库时,数据引用(全局变量,类vtables等)总是被解析。代码引用在一些系统上首次使用时被解析(延迟查找;至少在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()
{
// ...
}

externCC * createC )
{
return new D();
}

现在,在主程序中, c $ c> dlopen ,使用 dlsym 获取 createD 的函数指针并调用获取对象。当所有对象都消失后,您可以调用 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<<暂停;
}
return 0;
}


I figure out I can have the implementation of parts of a class in a shared lib, as far as the symbols are loaded when used.

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() {
...
}

This works fine.

However once I finished using C::method(), I would like to unload it, so I can change, recompile and reload it without having to restart the main program

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; 
}

The problem is that it does not unload the library when doing the first dlclose, probably because an instance of my class C exists. Any way to force this?

(using g++ 4.2.3, on Linux Ubuntu 10.04)

解决方案

Short Answer

It won't work the way you are doing it. There might also be other problems with your approach that haven't bitten you yet.

Why it doesn't work

Undefined symbols in your program/library are resolved at different times. On most systems, data references (global variables, class vtables, etc.) are always resolved when your program/library is loaded. Code references are resolved when they are first used on some systems ("lazy lookup"; it happens on Linux and Mac OS X, at least), unless some special options are set (RTLD_NOW parameter for dlopen or LD_BIND_NOW environment variable). Once these are resolved, no new lookup will take place.

If you dlopen your library with the RTLD_GLOBAL flag before the lazy lookup for a method is done, the method from your library will be used. The code reference to the method is now resolved; it won't change again. Your main program now officially uses symbols from your dlopened library, so dlclose will no longer close the library - dlclose only drops your explicit handle to it.

In short, you should only ever expect to unload libraries that you only use via explicit calls to dlsym.

What to do instead

What you can do instead is have your library provide a derived class implementation. You'd define your class C as an abstract base class:

class C
{
public:
    virtual void method();
};

In your separately-compiled library, you'd define a derived class and a function that creates an object of that derived class:

class D : public C
{
public:
    virtual void method();
};

void D::method()
{
    // ...
}

extern "C" C* createC()
{
    return new D();
}

Now, in your main program, you'd load the library using dlopen, get a function pointer to createD using dlsym and call it to get an object. When all objects are gone, you can call dlclose, recompile your library, and do the whole thing again:

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;
}

这篇关于C ++:在分离的共享库中实现类方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆