статическая инициализация

контекст

Я работаю над проектом, имеющим некоторые "модули". Что я называю, модуль вот простой класс, реализовывая особую функциональность и derivating от абстрактного класса GenericModule, которые вызывают интерфейс.

Новые модули, как предполагается, добавляются в будущем.

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

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

контекст ² (технический)

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

мое решение

Я нашел вдохновение в том, что они сделали с тестом Google.

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

class CModuleFactory : boost::noncopyable
{
public:
    virtual ~CModuleFactory() {};

    virtual CModuleGenerique* operator()(
        const boost::property_tree::ptree& rParametres ) const = 0;
};

template 
class CModuleFactoryImpl : public CModuleFactory
{
public:
    CModuleGenerique* operator()(
        const boost::property_tree::ptree& rParametres ) const
    {
        return new T( rParametres );
    }
};

и метод предположил, чтобы зарегистрировать модуль и добавить, что это - фабрика к списку.

class CGenericModule
{
    // ...
    template 
    static int declareModule( const std::string& rstrModuleName )
    {
        // creation de la factory
        CModuleFactoryImpl* pFactory = new CModuleFactoryImpl();

        // adds the factory to a map of "id" => factory
        CAcquisition::s_mapModuleFactory()[rstrModuleName ] = pFactory;

        return 0;
    }
};

теперь в модуле все я должен сделать, чтобы объявить, что модуль:

static int initModule =
acquisition::CGenericModule::declareModule(
    "mod_name"
    );

(в будущем это будет перенесено в макрос, позволяющий сделать

DECLARE_MODULE( "mod_name", acquisition::modules::CMyMod );

)

проблема

Allright теперь проблема.

Вещь, она работает, но не точно способ, которым я хотел бы.

Метод declareModule не называют, если бы я поместил определение initModule в .cpp модуля (где я хотел бы иметь его) (или даже в.h). Если я поместил статический init в используемый .cpp файл..работает.

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

Вещью является Visual Studio, кажется, отбрасывает весь obj при создании библиотеки. Я предполагаю поэтому, что это не используется нигде.

Я активировал подробное соединение, и в передаче n°2 это перечисляет .objs в библиотеке, и .obj модуля не там.

почти разрешенный?

Я нашел это и попытался добавить /OPT:NOREF опция, но это не работало. Я не пытался поместить функцию в.h модуля и назвать его откуда-либо, потому что самым главным является способность объявить это в одной строке в, он - файл.

Также я думаю, что проблема подобна этому, но решение для g ++ не визуально :'(

править: Я просто считал ответную ноту в этот вопрос. Хорошо, если я #include.h модуля от другого .cpp, и помещенный init в.h модуля. Это работает, и инициализация на самом деле сделана дважды... однажды в каждой единице компиляции? хорошо кажется, что это происходит в единице компиляции модуля...

сторона отмечает

Если Вы не соглашаетесь с тем, что я пытаюсь сделать, упал свободный сказать, но я все еще интересуюсь решением

6
задан Community 23 May 2017 в 12:13
поделиться

2 ответа

У меня есть нечто подобное, основанное на коде из wxWidgets, однако я использовал его только как DLL. Однако код wxWidgets работает со статическими библиотеками.

Самое важное, что может иметь значение, это то, что в wx эквивалент следующего определяется в области видимости класса.

static int initModule =
acquisition::CGenericModule::declareModule<acquisition::modules::CMyMod>(
    "mod_name"
    );

Что-то вроде следующего, где создание Factory, поскольку он статичен, приводит к его загрузке в список Factory.

#define DECLARE_CLASS(name)\
class name: public Interface { \
    private: \
        static Factory m_reg;\
        static std::auto_ptr<Interface > clone();

#define IMPLEMENT_IAUTH(name,method)\
    Factory name::m_reg(method,name::clone);\
1
ответ дан 17 December 2019 в 18:09
поделиться

Если хотите при таком поведении саморегистрации в ваших «модулях» ваше предположение, что компоновщик оптимизирует initModule, потому что на него нет прямых ссылок, может быть неверным (хотя оно также может быть правильным :-).

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

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

static vector<string> unsafe_static; // bad

vector<string>& safe_static()
{
    static vector<string> f;
    return f;
} // ok

Обратите внимание, что у приведенного выше есть проблемы с параллелизмом. Некоторая синхронизация потоков необходима для нескольких потоков, вызывающих safe_static.

Я подозреваю, что ваша настоящая проблема связана с порядком инициализации, даже если может показаться, что определение initModule исключается компоновщиком. Обычно линкеры не пропускают ссылки, которые имеют побочные эффекты.

Если вы обнаружите, что это не проблема порядка инициализации и что код опускается компоновщиком, то один из способов принудительно это экспортировать initModule (например, dllexport в MSVC). Вам следует хорошо подумать, действительно ли такое поведение при саморегистрации перевешивает простой процесс добавления в список вызовов функций для инициализации ваших «модулей». Вы также могли бы добиться этого более естественно, если бы каждый «модуль» был определен в отдельной разделяемой библиотеке / DLL, и в этом случае ваш макрос мог бы просто определять функцию для экспорта, которая может быть добавлена ​​автоматически хост-приложением. Конечно, это связано с необходимостью определения отдельного проекта для каждого «модуля», который вы создаете, в отличие от простого добавления саморегистрирующегося файла cpp к существующему проекту.

2
ответ дан 17 December 2019 в 18:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: