В основной программе я dlopen и dlclose (LoadLibrary и FreeLibrary соответственно) совместно используемой библиотекой. Общая библиотека содержит статическую переменную, которая создается на dlopen и уничтожается на dlclose. Такое поведение согласуется с MSVC 2008 и 2013, GCC 3.4.6 и Sunstudio 12.1. Однако с GCC 4.9.1 и GCC 5.2.1 деструктор больше не вызывался на dlclose. Вместо этого он вызывается перед выходом программы.Деструктор глобальной статической переменной в общей библиотеке не вызывается в dlclose
Особенность класса статических переменного, то, что в конструкторе, есть вызов шаблонных функций получить (в глобальном масштабе), которая возвращает локальную статический переменную.
Я был в состоянии воспроизвести такое поведение со следующим файлом один CPP скомпоновать в общей библиотеку:
#include <iostream>
template <typename T> // In my actual code, i is of type T, however, this has no effect
int get()
{
static int i = 0;
return i;
}
class Dictionary {
public:
Dictionary()
{
std::cout << "Calling Constructor" << std::endl;
get<int>();
}
~Dictionary(){
std::cout << "Calling Destructor" << std::endl;
}
private:
Dictionary(const Dictionary&);
Dictionary& operator=(const Dictionary&);
};
static Dictionary d;
Я исследовал ухищрения, которые могут быть сделаны для того, чтобы иметь деструктор призвал dlclose, и пришел к выводу, следующее:
- Если функция получить не шаблонный
- иначе, если переменная я в функции получить не был статичным
- иначе, если функция получить выполнена статической
кода основной программы заключается в следующем:
#include <dlfcn.h>
#include <cassert>
#include <string>
#include <iostream>
void* LoadLib(std::string name)
{
void* libInstance;
name = "lib" + name + ".so";
libInstance = dlopen(name.c_str(), RTLD_NOW);
if (! libInstance) std::cout << "Loading of dictionary library failed. Reason: " << dlerror() << std::endl;
return libInstance;
}
bool UnloadLib(void* libInstance)
{
int ret = dlclose(libInstance);
if (ret == -1)
{
std::cout << "Unloading of dictionary library failed. Reason: " << dlerror() << std::endl;
return false;
}
return true;
}
int main()
{
void* instance = LoadLib("dll");
assert(instance != 0);
assert(UnloadLib(instance));
std::cout << "DLL unloaded" << std::endl;
}
Я построил двоичные файлы с помощью следующих команд:
g++ -m64 -g -std=c++11 -shared -fPIC dll.cpp -o libdll.so
g++ -m64 -g -std=c++11 -ldl main.cpp -o main.out
Выход, который я получаю, когда деструктор вызывается перед выходом программы, является fo llowing:
Calling Constructor
DLL unloaded
Calling Destructor
выход я получаю, когда деструктор вызывается dlclose следующая:
Calling Constructor
Calling Destructor
DLL unloaded
Вопросы:
- Если изменение поведения между версиями GCC является не ошибка, не могли бы вы объяснить, почему деструктор не вызвал dlclose?
- Можете ли вы объяснить, почему каждый двоеточие: почему деструктор называется dlclose в этом случае?
звучит как сообщение об ошибке, вы должны сделать против GCC – GreatAndPowerfulOz
статических переменных теперь потокобезопасная (они должны быть из-за Стандартные изменения C++, введенные в C++ 11). Возможно, это имеет значение. В Visual Studio 2013 этого не было реализовано, в то время как 2015 год. Может быть, вам следует протестировать с 2015 года. Только gcc 4.x и выше реализовали это, поэтому вы должны увидеть, играет ли статическая переменная потоковое требование. – PaulMcKenzie