解决初始化顺序:
首先,这只是一个临时的解决方法,因为你有全局变量,你试图摆脱但还没有时间(你最终会摆脱它们不是吗?:-)
class A
{
public:
// Get the global instance abc
static A& getInstance_abc() // return a reference
{
static A instance_abc;
return instance_abc;
}
};
这将保证它在首次使用时被初始化并在应用程序终止时被销毁。
多线程问题:
C++11确实保证这是线程安全的:
§6.7 [stmt.dcl] p4
如果在初始化变量时控制同时进入声明,则并发执行应等待初始化完成。
但是,C++03 并没有官方保证静态函数对象的构造是线程安全的。因此,从技术上讲,该getInstance_XXX()
方法必须使用临界区加以保护。从好的方面来说,gcc 有一个显式补丁作为编译器的一部分,它保证每个静态函数对象即使在存在线程的情况下也只会被初始化一次。
请注意:不要使用双重检查锁定模式来尝试避免锁定成本。这在 C++03 中不起作用。
创建问题:
在创建时,没有问题,因为我们保证它是在使用之前创建的。
破坏问题:
在对象被销毁后访问对象存在潜在问题。仅当您从另一个全局变量的析构函数访问对象时才会发生这种情况(全局,我指的是任何非局部静态变量)。
解决方案是确保您强制执行破坏顺序。
请记住,破坏顺序与构造顺序完全相反。所以如果你在你的析构函数中访问对象,你必须保证这个对象没有被销毁。为此,您必须保证在构造调用对象之前完全构造对象。
class B
{
public:
static B& getInstance_Bglob;
{
static B instance_Bglob;
return instance_Bglob;;
}
~B()
{
A::getInstance_abc().doSomthing();
// The object abc is accessed from the destructor.
// Potential problem.
// You must guarantee that abc is destroyed after this object.
// To guarantee this you must make sure it is constructed first.
// To do this just access the object from the constructor.
}
B()
{
A::getInstance_abc();
// abc is now fully constructed.
// This means it was constructed before this object.
// This means it will be destroyed after this object.
// This means it is safe to use from the destructor.
}
};