【发布时间】:2010-12-07 16:57:51
【问题描述】:
如果我在不同的编译单元中有两个静态变量,那么它们的初始化顺序是没有定义的。这一课很好学。
我的问题是:当第一个变量被初始化时,所有静态变量是否都已分配。换句话说:
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;
}
因此,该类从 Qt 库中获取了一个静态的 QMetaObject 实例:Subclass::staticMetaObject - 我认为它是在 Q_OBJECT 宏中自动生成的。然后FACTORY 宏创建一个静态ConcreteFactory< Subclass > 实例。 ConcreteFactory 在其构造函数中尝试引用 Subclass::staticMetaObject。
我对 linux (gcc) 上的这个实现非常满意,直到我用 Visual Studio 2008 编译它。由于某种原因,AbstractFactory::m_Map 在运行时为空,调试器不会在工厂构造函数中中断。
这就是引用其他静态变量的静态变量的气味的来源。
如何优化此代码以避免所有这些陷阱?
【问题讨论】:
-
好吧,这段代码与你原来的问题完全不同......在你原来的问题中,你存储了一个全局变量的地址,但直到
main才访问它,到那时全球已全面建成。但是现在您尝试从全局ConcreteFactory对象的构造函数内部使用它,这比main早得多。 -
在详细的例子中我存储了静态变量
staticMetaObject的地址。但它是在运行时通过create函数从main访问的——正如我在简化示例中描述的那样。我不关心static QMap<...> m_Map- 正如@Martin York 所建议的那样,我的真实代码实际上被包装到一个静态函数中。所以详细的例子是关于从ConcreteFactory构造函数中引用staticMetaObject。
标签: c++ variables static initialization