dlclose () no funciona con la función de fábrica y la función estática compleja en la función?
Estoy creando un marco de plugin simple en el que me gustaría poder abrir una biblioteca compartida (es decir, un plugin), inspeccionar y usar las funciones de fábrica que se proporcionan y finalmente cerrar (), sin dejar rastro.
Mi sistema de fábrica es trivial, con una única función exportada que devuelve un puntero a una clase Base común. Para comprobar que el complemento se haya descargado correctamente, tengo un objeto estático cuyo destructor establece un bool del programa principal.
Aquí está el programa principal:
// dltest.cpp follows. Compile with g++ -std=c++0x dltest.cpp -o dltest -ldl
#include <dlfcn.h>
#include <iostream>
using namespace std;
int main(int argc, char** argv)
{
if (argc > 1)
{
void* h = dlopen(argv[1], RTLD_NOW|RTLD_LOCAL);
if (!h)
{
cerr << "ERROR: " << dlerror() << endl;
return 1;
}
bool isFinilized = false;
*(bool**)dlsym(h, "g_finilized") = &isFinilized;
cout << boolalpha << isFinilized << endl;
if (dlclose(h))
{
cerr << "ERROR: " << dlerror() << endl;
return 2;
}
cout << boolalpha << isFinilized << endl;
}
return 0;
}
Y el código del plugin es:
// libempty.cpp follows. Compile with g++ -std=c++0x libempty.cpp -o libempty.so -fPIC -shared
#include <iostream>
#include <vector>
using namespace std;
bool* g_finilized = nullptr;
struct Finilizer
{
~Finilizer()
{
cout << "~Finilizer()" << endl;
if (g_finilized) *g_finilized = true;
}
} g_finilizer;
class Base
{
public:
virtual void init() = 0;
};
class Foo: public Base
{
virtual void init()
{
static const vector<float> ns = { 0.f, 0.75f, 0.67f, 0.87f };
}
};
extern "C" __attribute__ ((visibility ("default"))) Base* newBase() { return new Foo; }
Si se ejecuta, la salida es:
false
false
~Finilizer()
Esto muestra que la llamada a dlclose () no funciona como se esperaba y que la biblioteca no se descargó hasta que se cerró el programa.
Sin embargo, si movemos el vector hacia afuera de la función, entonces las últimas 8 líneas leen:
class Foo: public Base
{
virtual void init()
{
}
};
static const vector<float> ns = { 0.f, 0.75f, 0.67f, 0.87f };
extern "C" __attribute__ ((visibility ("default"))) Base* newBase() { return new Foo; }
Entonces dlclose () funciona correctamente y la salida es:
false
~Finilizer()
true
Se generan los mismos resultados si el vector se deja en la función pero no se exporta ninguna fábrica:
class Foo: public Base
{
virtual void init()
{
static const vector<float> ns = { 0.f, 0.75f, 0.67f, 0.87f };
}
};
//extern "C" __attribute__ ((visibility ("default"))) Base* newBase() { return new Foo; }
Se encuentran resultados positivos si el vector se sustituye con una matriz C:
class Foo: public Base
{
virtual void init()
{
static const float ns[] = { 0.f, 0.75f, 0.67f, 0.87f };
}
};
extern "C" __attribute__ ((visibility ("default"))) Base* newBase() { return new Foo; }
¿Es este un error en GCC / Linux? ¿Hay alguna solución para que los objetos complejos puedan declararse estáticamente en una función miembro de una clase factorizada?