Статические члены статических библиотек

У меня есть статическая библиотека со статическим членом. Эта библиотека статически связана с основным приложением и одним из его плагинов. Похоже, статическая переменная инициализируется как в основной (приложение), так и в dll (плагин).

Вопрос: как избежать повторной инициализации статической переменной при загрузке динамической библиотеки. Или мне не хватает чего-то простого?

Дополнительная информация:

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

orbhelper.h

class ORBHelper {
    static std::string sss_;
public:
    static std::string getStr();
    static void setSTR(std::string str);
};

orbhelper.cpp

std::string ORBHelper::sss_ = "init";

static std::string ORBHelper::getStr()
{
    std::cerr << "get " << sss_.c_str() << std::endl;
    return sss_;
}
static void ORBHelper::setSTR(std::string str)
{
    sss_ = str;
    std::cerr << "set " << sss_.c_str() << std::endl;
}

Эта библиотека используется в main.cpp, а также в другой динамической библиотеке, которая загружается в main. В main.cpp я устанавливаю статическую строку и в одной из функций динамической библиотеки хочу ее получить.

Установка статической переменной в main:

main.cpp

...
ORBHelper::setStr("main");
std::cerr << ORBHelper::getStr().c_str() << std::endl; //prints 'main'
//then loading library
...

Затем получаем значение переменной в dll:

hwplugin.cpp

...
std::cerr << ORBHelper::getStr().c_str() << std::endl; //prints 'init' instead of 'main'
...

Похоже, статическая переменная была инициализирована дважды. Первый - перед main.cpp, второй - при загрузке динамической библиотеки. Статическая библиотека со статическим классом, связанная как с основным приложением, так и с динамической библиотекой.

P.S. в моем вопросе слишком много слов "статика", я знаю =)


person uni    schedule 12.05.2012    source источник
comment
Если вы связываете статически, вы, вероятно, получите два экземпляра переменной, один в exe и один в DLL.   -  person Bo Persson    schedule 12.05.2012
comment
Я проверил адрес переменной (printf (% p, & sss);) и обнаружил, что это та же самая переменная.   -  person uni    schedule 12.05.2012
comment
У меня недавно была такая же проблема (stackoverflow.com/q/10520587/509868); есть два полезных решения (1: превратить статическую библиотеку во (вторую) DLL; или 2: добавить функцию в существующую DLL, которая инициализирует проблемный материал в статической библиотеке)   -  person anatolyg    schedule 12.05.2012
comment
Если у вас есть загрузка во время выполнения, может быть предпочтительнее создать некоторый глобальный объект контекста в вашем основном приложении, а затем передать ссылку или указатель на него для инициализации вашей динамической библиотеки. Объект контекста может легко содержать достаточно информации о состоянии, чтобы каждая загруженная библиотека могла выяснить, нужно ли ей выполнять больше работы.   -  person Kerrek SB    schedule 12.05.2012


Ответы (1)


Да, у вас есть два экземпляра вспомогательного класса.

Библиотека DLL должна быть связана с исполняемым файлом, который связывает статический класс, и использовать его для разрешения вспомогательного класса. Не связывайте DLL со статической библиотекой, а связывайте ее с самим исполняемым файлом.

person Antti Huima    schedule 12.05.2012
comment
Вы не можете этого сделать, вы получите ошибки компоновщика при сборке dll. - person Matteo Italia; 12.05.2012
comment
Я добавил printf (% p, & sss_); в каждой функции помощника и каждый раз, когда он печатает один и тот же адрес. Разве это не значит, что существует только один экземпляр помощника? - person uni; 12.05.2012
comment
Хм ... возможно, но тогда это статический инициализатор, который все равно запускается дважды, даже если символы отображаются на один и тот же адрес памяти. - person Antti Huima; 12.05.2012