是否有可能在真正需要时初始化Singleton的实例?
考虑这种模式取自着名的“设计模式”:
class Singleton {
public:
static Singleton* Instance();
protected:
Singleton();
private:
static Singleton* _instance;
}
Singleton* Singleton::_instance = 0; // unit.cpp
static Singleton* Singleton::Instance() {
if (_instance == 0) {
_instance = new Singleton;
}
return _instance;
}
现在,我认为那里的模式存在问题,如果有人希望将库中的Singleton提供给其他人:如果用户从另一个编译单元调用Singleton::Instance()
(在静态数据成员初始化期间,例如,在初始化_instance之前,Singleton::Instance()
的后续调用可能会创建Singleton的另一个实例,并产生不需要的结果,因为_instance可能已经初始化为0。
我认为一种解决方案是以这种方式初始化_instance:
Singleton* Singleton::_instance = Singleton::Instance();
无论如何,对于那些不需要调用Singleton :: Instance()初始化静态数据的人来说,初始化不是“懒惰”。
是否有更好的解决方案,以便在需要Singleton实例时可以进行初始化?
答案 0 :(得分:7)
您引用的单身人士解决方案有效,因为
Singleton* Singleton::_instance = 0;
描述了静态初始化(在这种情况下是零初始化,但常量初始化在使用时也会起作用),这是保证在任何动态初始化之前发生(因此在运行任何代码之前)。这里保证了静态初始化的所有要求,因为_instance是内置类型(指针)的全局变量,并用零初始化。
你提供的另一个解决方案没有改变任何重要的东西,因为在调用其他模块的代码之前,仍然只保证_instance的零初始化,因为Singleton :: Instance调用的初始化是动态的,因此受static initialization order fiasco。
约束注意:静态初始化通常是通过将变量的值(可编译的编译时间)存储在可执行文件的data segment中来实现的。
虽然大多数程序员(包括Bjarne Stroustrup)调用原始单例实现“编译时初始化”中使用的初始化样式,但标准将其称为“静态初始化”,而不是“动态初始化”(这是什么是最常被称为运行时间。见C++0x draft 3.6.2(缩写,强调我的):
3.6.2非局部变量的初始化 [basic.start.init]
...初始化具有静态存储持续时间的非局部变量 作为计划启动的结果。 ......如下。
2具有静态存储持续时间(3.7.1)的变量...应为零初始化(8.5) 在进行任何其他初始化之前。
执行常量初始化: ...
- 如果构造函数调用未初始化具有静态或线程存储持续时间的对象,并且其初始化程序中出现的每个完整表达式都是常量表达式。
零初始化和常量初始化一起称为静态初始化;所有其他初始化是 动态初始化。在进行任何动态初始化之前,应执行静态初始化。
答案 1 :(得分:4)
现在,如果有人愿意,我认为那里的模式存在问题 将库中的Singleton提供给其他人:如果用户调用 来自另一个编译单元的Singleton :: Instance()(在静态期间) 例如,在_instance之前的数据成员初始化 初始化,然后调用Singleton :: Instance()可能 因为,创建了Singleton的另一个实例,带有不需要的结果 _instance可能已经初始化为0。
没问题:在进行任何动态初始化之前,静态变量零初始化。
另一方面,您引入的代码作为解决不存在的问题,即
Singleton* Singleton::_instance = Singleton::Instance();
有问题 - 无法保证翻译单位之间(动态)初始化的顺序。
干杯&第h。,
答案 2 :(得分:2)
使用本地静态
Singleton* Singleton::getInstance()
{
static Singleton obj; return &Singleton;
}