If I have two static variables in different compilation units, then their initialization order is not defined. This lesson is well learned.
The question I have: are all the static variables already allocated, when the first one is being initialized. In other words:
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();
}
Will b_ptr point to a valid piece of memory, where B is allocated and initialized at the time of the execution of the main function? On all the platforms?
Longer story:
The compilation unit 1 is Qt library. The other one is my application. I have couple QObject derived classes, that I need to be able to instantiate by the class name string. For this I came up with a templated factory class:
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;
Then I add this macro on every QObject subclass definition:
class Subclass : public QObject {
Q_OBJECT;
FACTORY(Subclass);
}
Finally I can instantiate a class by the type name:
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;
}
So the class gets a static QMetaObject
instance: Subclass::staticMetaObject
from the Qt library - it is auto-generated in Q_OBJECT
macro I think. And then the FACTORY
macro creates a static ConcreteFactory< Subclass >
instance. ConcreteFactory in its constructor tries to reference of Subclass::staticMetaObject.
And I was pretty happy with this implementation on linux (gcc), until I compiled it with Visual Studio 2008. For some reason AbstractFactory::m_Map was empty on the runtime, and the debugger would not break at the factory constructor.
So this is where the smell of static vars referencing other static vars is coming from.
How can I optimize this code to avoid all these traps?
Yes, the standard allows this.
There are a number of paragraphs in section [basic.life]
which start out
Before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that refers to the storage location where the object will be or was located may be used but only in limited ways.
and there is a footnote which indicates that this specifically applies to your situation
For example, before the construction of a global object of non-POD class type
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With