C ++: реализация методов класса в отдельной разделяемой библиотеке - PullRequest
7 голосов
/ 10 января 2012

Я выяснил, что у меня может быть реализация частей класса в разделяемой библиотеке, поскольку символы загружаются при использовании.

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 (), я хотел бы выгрузить его, чтобы я мог изменить, перекомпилировать и перезагрузить его без перезапуска основной программыне выгружать библиотеку при первом выполнении dlclose, вероятно, потому что существует экземпляр моего класса C.Любой способ заставить это?

(с использованием g ++ 4.2.3, в Linux Ubuntu 10.04)

Ответы [ 2 ]

10 голосов
/ 11 января 2012

Короткий ответ

Это не сработает так, как вы это делаете.В вашем подходе могут быть и другие проблемы, которые вас еще не укусили.

Почему это не работает

Неопределенные символы в вашей программе / библиотеке решаются в разное время.В большинстве систем ссылки на данные (глобальные переменные, таблицы классов и т. Д.) Всегда разрешаются при загрузке вашей программы / библиотеки.Ссылки на код разрешаются, когда они впервые используются в некоторых системах («отложенный поиск»; по крайней мере, это происходит в Linux и Mac OS X), если не установлены некоторые специальные параметры (параметр RTLD_NOW для dlopen или переменная среды LD_BIND_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;
}
0 голосов
/ 21 марта 2019

Спасибо за помощь, ребята, просто замечание:

Не забудьте в классе C инициализировать метод на ноль (этот класс отсутствует в общей библиотеке) и установить виртуальный разрушитель по умолчанию

Если вы хотите узнать, какой флаг равен 0 для dlopen -> это RTLD_LOCAL

...