Использование объектов приложения из общего объекта

Я сейчас немного запутался. Вчера у меня были неопределенные символы, даже если я использовал -rdynamic с g ++. Но сейчас у меня нет никаких ошибок, и это еще более тревожно.

Чтобы немного объяснить мой случай, я хочу создать своего рода плагин, например общий объект. Я еще не решил, как лучше поступить.

A) Все мои общие объекты имеют функцию, называемую регистром, которая будет вызываться с параметром. Это будет менеджер плагинов.

Б) Мой общий объект определит класс и создаст его экземпляр во время загрузки. В конструкторе этого класса он попытается получить статический синглтон из приложения и автоматически зарегистрируется.

Насколько я могу судить, мои первые попытки пока были не такими уж хорошими.

main.cpp

#include "main.hpp"
#include <iostream>
#include <cstdio>
#include <dlfcn.h>

int S::shared = 0;

int main(int argc, char** argv){
    std::cout << "In main -> " << S::shared << "\n";

    void* triangle = dlopen("./libtwo.so", RTLD_LAZY);

    if(triangle == NULL){
        std::cout << "Error while loading so file\n" << dlerror() << "\n";
    }

    std::cout << "In main -> " << S::shared << "\n" << triangle;
    return 0;
}

main.hpp

class S {
    public:
    static int shared;

    S(){
        S::shared = 0;
    };
};

two.cpp

#include "main.hpp"
#include <iostream>

class MyObject {
    public:
    MyObject(){
        std::cout << "In two -> " << S::shared  << "\n";
    }
};

MyObject t();

В этом примере S :: shared - это статический объект, которым я бы поделился. Для этого простого теста я использую только int, но в будущем это будет экземпляр класса.

Моя единственная попытка разобраться в случае А) была ошибкой ... Я действительно не знаю, что я пропустил.

// Результаты на текущий момент (сегодня)

piplup@vika:~/dev/WebDesign/Scproci$ scons -Q
g++ -o two.os -c -fPIC two.cpp
g++ -o libtwo.so -shared two.os
g++ -o main.o -c -fPIC main.cpp
g++ -o main -Wl,--export-dynamic main.o -ldl
piplup@vika:~/dev/WebDesign/Scproci$ ./main
In main -> 0
In main -> 0

person Loïc Faure-Lacroix    schedule 22.08.2011    source источник
comment
учитывая, что вы показываете только код для второго метода, он ведет себя так, как ожидалось, в зависимости от того, что показано.   -  person diverscuba23    schedule 22.08.2011
comment
Почему не отображается «Через два» - ›0?   -  person Loïc Faure-Lacroix    schedule 22.08.2011
comment
Неопределенный символ произойдет, поскольку S :: shared определен в main.cpp, но при связывании libtwo.so вы не включили main.o там, где он был определен.   -  person Flame    schedule 22.08.2011
comment
Вы не можете создать функции с именем _init и _fini (старый способ) или функцию, экспортированную __attribute __ ((конструктор)) и __attribute __ ((деструктор)) (новый способ). _Init вызывается при загрузке библиотеки, _fini - непосредственно перед ее выгрузкой.   -  person diverscuba23    schedule 22.08.2011
comment
@Flame: Нет, когда библиотека загружена, она разрешит S ::, совместно используемый с основным исполняемым файлом, при первом обращении к нему (RTLD_LAZY). К сожалению, когда библиотека загружается, если для нее явно не указан код инициализации, она не выполняет никакой инициализации, кроме статической инициализации, которая может быть выполнена во время компиляции (т.е. простое присвоение переменных POD).   -  person diverscuba23    schedule 22.08.2011
comment
Ваши комментарии должны быть ответом.   -  person Flame    schedule 22.08.2011
comment
doc.powerdns.com/backend-writers-guide.html Я пытаюсь переделать эту вещь. Я попробую _init _fini, но я хотел бы воспроизвести то, что они там сделали.   -  person Loïc Faure-Lacroix    schedule 22.08.2011


Ответы (2)


#include "main.hpp" 
#include <iostream>  

class MyObject {     
    public:     
        MyObject(){         
            std::cout << "In two -> " << S::shared  << "\n";     
        } 
};  

MyObject* t;

__attribute__((constructor))
void init_two()
{
    t = new MyObject();
}

__attribute__((destructor))
void uninit_two()
{
    delete t;
}

Это должно дать ожидаемый результат. Указатели используются, поскольку с ними легче работать явно в общих объектах, поскольку регулярная инициализация не происходит автоматически. Если вы не хотите использовать указатели, предоставьте явную инициализацию для вашего класса и вызовите ее в функции инициализации разделяемой библиотеки.

* РЕДАКТИРОВАТЬ *

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

чтобы вы могли изменить свой:

MyObject t();

позвонить:

MyObject t;

и он будет работать без явного определения функций инициализации.

or

class MyObject {
public:
   MyObject() { /* as before */ };
   MyObject(int val)
   {
        S::shared = val;
        std::cout << "In two -> " << S::shared << "\n";
   }
};

MyObject t(10);

Похоже, что компилятор не понимает, является ли MyObject t (); является объявлением переменной или объявлением функции в глобальной области видимости и обрабатывает его как объявление функции.

person diverscuba23    schedule 22.08.2011
comment
Я еще не помечаю это как ответ. см. мой комментарий в вопросе. Пока как упоминалось. Вероятно, это лучший способ сделать это. Определение того, как загружаются общие объекты, кажется довольно расплывчатым и может зависеть от одного компилятора к другому. Явное определение функций загрузки и разгрузки, вероятно, в любом случае является самым безопасным. - person Loïc Faure-Lacroix; 22.08.2011
comment
Я нашел такой же результат. MyObject t () не будет работать, но неявный будет работать. Однако это действительно интересный случай. - person Loïc Faure-Lacroix; 23.08.2011

Проблема, которая сразу бросается в глаза, заключается в том, что вам нужно разделять блоки ссылок. Статический член класса - это просто глобальный объект, заключенный в пространство имен этого класса.

Теперь, если у вас есть два блока ссылок, скажем, основная программа и общий объект, вполне возможно, что у них обоих будет глобальный foo, и они будут разными значениями.

Кроме того, неясно, почему статическая инициализация t в two.cpp не выполняется в общем объекте, вероятно, это не гарантировано произойдет до некоторого типа основной функции в общем объекте.

person Flame    schedule 22.08.2011
comment
двух foo не будет, поскольку в моем примере экземпляр S :: shared создается только в main.cpp. Он будет хорошо работать со статическими связанными объектами, но я понятия не имею, почему конструктор не вызывается - person Loïc Faure-Lacroix; 22.08.2011