Если у меня две статические переменные в разных единицах компиляции, то порядок их инициализации не определен. Этот урок хорошо усвоен.
У меня вопрос: все ли статические переменные уже выделены, когда инициализируется первая. Другими словами:
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();
}
Будет ли b_ptr указывать на допустимый фрагмент памяти, где B выделяется и инициализируется во время выполнения основной функции? На всех платформах?
Более длинная история:
Единицей компиляции 1 является библиотека Qt.
Другой мой заявка. У меня есть пара производных классов QObject, которые мне нужно иметь возможность создавать в виде строки имени класса. Для этого я придумал шаблонный фабричный класс:
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;
Затем я добавляю этот макрос в каждое определение подкласса QObject:
class Subclass : public QObject {
Q_OBJECT;
FACTORY(Subclass);
}
Наконец, я могу создать экземпляр класса по имени типа:
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;
}
Таким образом, класс получает статический экземпляр QMetaObject
: Subclass::staticMetaObject
из библиотеки Qt - я думаю, он автоматически генерируется в макросе Q_OBJECT
. И тогда макрос FACTORY
создает статический экземпляр ConcreteFactory< Subclass >
. ConcreteFactory в своем конструкторе пытается ссылаться на Subclass :: staticMetaObject.
И я был очень доволен этой реализацией на linux (gcc), пока я не скомпилировал ее с Visual Studio 2008. По какой-то причине AbstractFactory :: m_Map был пуст во время выполнения, и отладчик не сломался в конструкторе фабрики.
Так вот откуда исходит запах статических переменных, ссылающихся на другие статические переменные.
Как я могу оптимизировать этот код, чтобы избежать всех этих ловушек?