Si tengo dos variables estáticas en diferentes unidades de compilación, entonces su orden de inicialización no está definida. Esta lección está bien aprendidaC++ Inicialización de variables estáticas (Una vez más)
La pregunta que tengo: son todas las variables estáticas ya asignadas, cuando la primera se está inicializando. En otras palabras:
static A global_a; // in compilation unit 1
static B global_b; // in compilation unit 2
struct A {
A() { b_ptr = &global_b; }
B *b_ptr;
void f() { b_ptr->do_something(); }
}
int main() {
global_a.f();
}
Se b_ptr punto a una pieza válida de la memoria, donde se asigna B y se inicializa en el momento de la ejecución de la función principal? En todas las plataformas? historia
más larga:
La unidad de compilación 1 es la biblioteca Qt. El otro es mi aplicación. Tengo un par de clases derivadas de QObject, que necesito poder instanciar por la cadena de nombre de clase. Para esto he venido para arriba con una clase de fábrica con plantilla:
class AbstractFactory {
public:
virtual QObject *create() = 0;
static QMap<const QMetaObject *, AbstractFactory *> m_Map;
}
QMap<const QMetaObject *, AbstractFactory *> AbstractFactory::m_Map; //in .cpp
template <class T>
class ConcreteFactory: public AbstractFactory {
public:
ConcreteFactory() { AbstractFactory::m_Map[&T::staticMetaObject] = this; }
QObject *create() { return new T(); }
}
#define FACTORY(TYPE) static ConcreteFactory <TYPE> m_Factory;
Luego añadir esta macro en cada definición subclase QObject:
class Subclass : public QObject {
Q_OBJECT;
FACTORY(Subclass);
}
fin puedo crear una instancia de una clase por el nombre del tipo:
QObject *create(const QString &type) {
foreach (const QMetaObect *meta, AbstractFactory::m_Map.keys() {
if (meta->className() == type) {
return AbstractFactory::m_Map[meta]->create();
}
}
return 0;
}
Así que la clase obtiene una instancia estática QMetaObject
: Subclass::staticMetaObject
de la biblioteca Qt - se genera automáticamente en Q_OBJECT
macro, creo. Y luego, la macro FACTORY
crea una instancia estática ConcreteFactory<Subclass>
. ConcreteFactory en su constructor intenta hacer referencia a Subclass :: staticMetaObject.
Y estuve muy contento con esta implementación en Linux (gcc), hasta que la compilé con Visual Studio 2008. Por alguna razón AbstractFactory :: m_Map estaba vacía en el tiempo de ejecución, y el depurador no se rompería en el constructor de la fábrica .
Así que aquí es donde viene el olor de los vars estáticos que hacen referencia a otros vars estáticos.
¿Cómo puedo optimizar este código para evitar todas estas trampas?
Bueno, este código es bastante diferente de su pregunta original ... en su pregunta original, almacenó la dirección de una variable global, pero no accedió hasta 'main', momento en el cual el global fue construido por completo. Pero ahora está intentando usarlo desde dentro del constructor de un objeto global 'ConcreteFactory', que es mucho más antiguo que' main'. –
En el ejemplo detallado, guardo la dirección de la variable estática 'staticMetaObject'. Pero se accede desde 'main' a través de la función' create' en el tiempo de ejecución, exactamente como lo describí en el ejemplo simplificado.No me preocupa el 'QMap estático <...> m_Map' - en mi código real está envuelto en una función estática tal como lo sugirió @Martin York. Entonces, el ejemplo detallado es sobre hacer referencia a 'staticMetaObject' del constructor' ConcreteFactory'. –