lazy初始化真的可能与静态数据成员吗? [英] Is lazy initialization really possible with static data members?

查看:213
本文介绍了lazy初始化真的可能与静态数据成员吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

可以在真正需要单例时初始化单例的实例。



考虑这种从着名的设计模式中获取的模式:

  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:如果用户在_instance之前从另一个编译单元(例如在静态数据成员初始化期间)调用 Singleton :: Instance()被初始化,然后下面的调用 Singleton :: Instance()可能会创建另一个Singleton的实例,带有不必要的结果,因为_instance可能已经初始化为0。 / p>

我认为一个解决方案是以这种方式初始化_instance:

  Singleton * Singleton :: _ instance = Singleton :: Instance(); 

无论如何,这使得初始化对于那些不需要调用Singleton的人来说是lazy



有没有更好的解决方案,以便在需要Singleton实例时可以发生初始化?




您引用的单例解决方案的工作原因是

  Singleton * Singleton :: _ instance = 0; 

描述了静态初始化 >在这种情况下,但是一个常量初始化也将工作,如果使用),这保证发生在任何动态初始化之前(因此在任何代码运行之前)。静态初始化的所有要求都在这里得到保证,因为_instance是内置类型(指针)的全局变量,并且初始化为零。



提供不改变任何重要的,因为仍然只有_instance的零初始化保证发生在来自其他模块的代码之前,因为Singleton :: Instance调用的初始化是一个动态的,因此受 static 初始化顺序fiasco



实现 - 数据段



注意:静态初始化通常通过存储变量的值来实现,时间,位于可执行文件的数据段中。



术语标准报价



虽然大多数程序员(包括 Bjarne Stroustrup )调用初始化样式中使用的原始单例实现编译时初始化,标准调用它静态初始化,而不是一个动态初始化(这是最常被称为运行时的)。请参见 C ++ 0x草案3.6.2 < a>(缩短,强调我):


3.6.2非局部变量的初始化 start.init]



...具有静态存储持续时间的非局部变量由于程序启动而初始化为
。 ...如下。



2具有静态存储持续时间(3.7.1)...的变量应在任何其他值之前进行零初始化(8.5)
将执行初始化。



执行常量初始化
...




  • 如果具有静态或线程存储持续时间的对象未通过构造函数调用初始化,并且初始化器中出现的每个完整表达式都是常量表达式。



零初始化和常量初始化称为静态初始化;所有其他初始化是
动态初始化。在发生任何动态初始化之前,必须执行静态初始化。



Is it possible to initialize the Instance of a Singleton when it is really needed?

Consider this pattern taken from the famous "Design Patterns":

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;
}

Now, I think there is a problem in the pattern there, if one desires to provide the Singleton in a library to others: if the user calls Singleton::Instance() from another compilation unit (during a static data member initialization, for example) before _instance is initialized, then a following call of Singleton::Instance() might create another instance of the Singleton, with unwanted results, since _instance might have been initialized to 0 first.

I think one solution is to initialize _instance this way:

Singleton* Singleton::_instance = Singleton::Instance();

Anyway, that makes the initialization not "lazy" for those who don't need to call Singleton::Instance() to initialize their static data.

Are there better solutions so that the inizialization can happen when the Singleton instance is needed?

解决方案

Static initialization happens before dynamic initialization

The singleton solution you have quoted works because

Singleton* Singleton::_instance = 0;

describes a static initialization (namely zero initialization in this case, but a constant initialization would work as well if used), which is guaranteed to happen before any dynamic initialization (and therefore before any code is run). All requirements of static initialization are guaranteed here, as _instance is a global variable of a built-in type (a pointer) and initialized with zero.

The other solution you have provided does not change anything significant, because still only the zero initialization of _instance is guaranteed to happen before code from other modules is called, as the initialization by Singleton::Instance call is a dynamic one and therefore is subject to static initialization order fiasco.

Implementation - data segment

Note: Static initialization is most often implemented by storing the value of the variable, which was computed compile time, in a data segment of the executable.

Terminology, standard quote

While most programmers (including Bjarne Stroustrup) call the initialization style used in the original singleton implemementation "compile time initialization", the standard calls it "static initialization", as opposed to a "dynamic initialization" (which is what is most often called run-time). See C++0x draft 3.6.2 (shortened, emphasis mine):

3.6.2 Initialization of non-local variables [basic.start.init]

... Non-local variables with static storage duration are initialized as a consequence of program initiation. ... as follows.

2 Variables with static storage duration (3.7.1) ... shall be zero-initialized (8.5) before any other initialization takes place.

Constant initialization is performed: ...

  • if an object with static or thread storage duration is not initialized by a constructor call and if every full-expression that appears in its initializer is a constant expression.

Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization. Static initialization shall be performed before any dynamic initialization takes place.

这篇关于lazy初始化真的可能与静态数据成员吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆