Обеспечение вызова статического метода перед main () - PullRequest
3 голосов
/ 03 июня 2011

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

В настоящее время это работает следующим образом: у меня есть класс с именем WorkerImplementationList со статическим методом:

template <typename T>
    WorkerImplementationList::registerWorkerFactoryMethod<T>(const std::string&)

, который хранит указатель на T::newInstance во внутренней структуре данных, которая будет получена фабрикой позже. В каждом из рабочих классов есть статический int с именем _dummyInstanceRegistrationVariable. В каждом из файлов .cc рабочих классов у меня есть следующая строка (на примере FooWorker):

int FooWorker::_dummyInstanceRegistrationVariable =
    WorkerImplementationList::registerWorkerFactoryMethod<FooWorker>("FooWorker");

Я хотел бы, чтобы статическая переменная была инициализирована перед созданием любых экземпляров класса. Кажется, это работает нормально, когда рабочий класс компилируется в тот же двоичный файл, который содержит main(). Однако, когда FooWorker находится в библиотеке (скажем, libblahapp_workers.a) и основной исполняемый файл связывает эту библиотеку, похоже, что _dummyInstanceRegistrationVariable не инициализируется до тех пор, пока не начнется main() (я предполагаю, что он инициализируется, когда первый экземпляр FooWorker построено), что слишком поздно для моих целей.

Я также пытался создать объект WorkerImplementationRegisterer<T> в глобальной области видимости, который регистрирует соответствующий тип работника при его создании, но здесь я снова сталкиваюсь с проблемами, когда рабочий класс находится в библиотеке, внешней по отношению к main(); этот глобально ограниченный объект не создается до начала main().

Статическое связывание моих рабочих библиотек решит эту проблему? Есть ли более элегантное решение, которое мне не хватает? Буду очень признателен за любую помощь.

Ответы [ 3 ]

3 голосов
/ 03 июня 2011

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

Это реальная проблема со статическими библиотеками, без универсального решения.

Вооружены знанием, что компоновщик захватываетсразу за весь модуль компиляции из библиотеки (во всех системах, которые я видел), вы, вероятно, сможете найти какой-то способ поместить эту глобальную переменную в необходимый модуль компиляции.

2 голосов
/ 03 июня 2011

iostreams в libstdc ++ используют для этого статическую переменную области файла.В заголовке iostream вы можете найти определение

static ios_base::Init __ioinit;

, которое заботится об инициализации iostreams в конструкторе (включая cin, cout, cerr).Посмотрите реализацию ios_base :: Init, она может дать вам несколько идей для работы.

2 голосов
/ 03 июня 2011

Я считаю, что лучше всего не предполагать, что что-то будет работать до main, и стараться не форсировать это. Лучший способ найти это - это инициализировать при первом вызове. Я бы создал статический метод в FooWorker с именем create и построил бы все экземпляры FooWorker через этот статический метод. Первое, что должен сделать метод create, это проверить, была ли инициализирована FooWorker::_dummyInstanceRegistrationVariable, а если нет, инициализировать ее.

Например:

main.cc

...
#include <FooWorker.hh>
...

int main(){
   ...
   FooWorker *fw = FooWorker::create(...);
   ...
   delete fw;
   ...
}

FooWorker.hh

...
class FooWorker{
  ...
  static int _dummyInstanceRegistrationVariable;
  ...
  FooWorker *create(/*args*/){
     if(_dummyInstanceRegistrationVariable == 0)
        _dummyInstanceRegistrationVariable = WorkerImplementationList::registerWorkerFactoryMethod<FooWorker>("FooWorker");
     ...
  }
  ...
};
...

FooWorker.cc

...
#include "FooWorker.hh"
...
int FooWorker::_dummyInstanceRegistrationVariable = 0;
...

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...