Tengo las siguientes clases que intentan implementar un Singleton genérico.G ++ obtiene el orden de destrucción de variables estáticas incorrecto
struct BaseObject
{
virtual ~BaseObject() {}
};
class _helper
{
private:
template<typename T> friend class Singleton;
set<BaseObject*> _s;
static _helper& _get()
{
static _helper t;
return t;
}
_helper()
{
cout<<" _helper ctor"<<endl;
}
~_helper()
{
cout<<" _helper dtor"<<endl;
//assert(_s.empty());
}
};
// Singleton<foo>::Instance() returns a unique instance of foo
template <typename T>
class Singleton : virtual private T
{
public:
static T& Instance()
{
static Singleton<T> _T;
return _T;
}
private:
Singleton()
{
cout<<"inserting into helper "<<typeid(T).name()<<" ptr "<<this<<endl;
assert(!_helper::_get()._s.count(this));
_helper::_get()._s.insert(this);
}
~Singleton()
{
cout<<"erasing from helper "<<typeid(T).name()<<" ptr "<<this<<endl;
assert(_helper::_get()._s.count(this));
_helper::_get()._s.erase(this);
}
};
Ahora si llamo Singleton< bar>::Instance()
seguido por Singleton< foo>::Instance()
, debería ver la siguiente salida:
inserting into helper 3bar ptr 0x509630
_helper ctor
inserting into helper 3foo ptr 0x509588
erasing from helper 3foo ptr 0x509588
erasing from helper 3bar ptr 0x509630
_helper dtor
Sin embargo, en algunos casos, veo lo siguiente:
inserting into helper 3bar ptr 0x509630
_helper ctor
inserting into helper 3foo ptr 0x509588
erasing from helper 3bar ptr 0x509630
_helper dtor
erasing from helper 3foo ptr 0x509588
Nótese que en el segundo caso, bar
y foo
se destruyó en el mismo orden en que se construyeron. Esto parece ocurrir cuando los foo
y bar
únicos se crean instancias dentro de una biblioteca compartida (.so) como referencias estáticas:
static bar& b = Singleton<bar>::Instance();
static foo& f = Singleton<foo>::Instance();
Cualquier idea por qué haría eso?
No creo que C++ haga ninguna garantía sobre el orden en que se llamarán los destructores de variables estáticas? –
¿Están en la misma unidad de traducción? – GManNickG
Tengo que poner algunos dólares de opinión aquí. Esta es una aplicación incorrecta del patrón singleton. El patrón singleton debe reservarse estrictamente para aquellos objetos que DEBEN ser solitarios dentro de un programa, no aplicados a algún objeto que simplemente exista solo una vez en el programa.Si desea un recurso de patrón singleton genérico, debe heredar FROM, lo que hace que el objeto no pueda existir en varias instancias. Si necesita un global, use uno. Singleton! = Variable global. –