Modern C++ Design 笔记 第六章 Implementing Singletons(1)

  1. #include <iostream>
  2. using namespace std;
  3.  
  4. /* Place holder for thread synchronization mutex */
  5. class Mutex
  6. {   /* placeholder for code to create, use, and free a mutex */
  7. };
  8.  
  9. /* Place holder for thread synchronization lock */
  10. class Lock
  11. {   public:
  12.         Lock(Mutex& m) : mutex(m) { /* placeholder code to acquire the mutex */ }
  13.         ~Lock() { /* placeholder code to release the mutex */ }
  14.     private:
  15.         Mutex & mutex;
  16. };
  17.  
  18. class Singleton
  19. {   public:
  20.         static Singleton* GetInstance();
  21.         int a;
  22.  
  23.     private:
  24.         Singleton(int _a) : a(_a) { cout << "In Ctor" << endl; }
  25.         ~Singleton() { cout << "In Dtor" << endl; }
  26.  
  27.         static Mutex mutex;
  28.  
  29.         // Not defined, to prevent copying
  30.         Singleton(const Singleton& );
  31.         Singleton& operator =(const Singleton& other);
  32. };
  33.  
  34. Mutex Singleton::mutex;
  35.  
  36. Singleton* Singleton::GetInstance()
  37. {
  38.     Lock lock(mutex);
  39.  
  40.     cout << "Get Inst" << endl;
  41.  
  42.     // Initialized during first access
  43.     static Singleton inst(1);
  44.  
  45.     return &inst;
  46. }
  47.  
  48. int main()
  49. {
  50.     Singleton* singleton = Singleton::GetInstance();
  51.     cout << "The value of the singleton: " << singleton->a << endl;
  52.     return 0;
  53. }
 在wikipedia上看到Singleton pattern的描述时偶然看到了一个Singleton的实现,局部的静态变量我们看到很多了。但是这里的mutex让人感觉有点不必要。  感觉 static Singleton inst(1);这个语句应该在loading的阶段就已经执行了,所以不存在所谓多线程的问题。但是实际上看了之后还是大吃一惊的。
  1.     // Initialized during first access
  2.     static Singleton inst(1);
  3. 00411F8C  mov         eax,dword ptr [$S1 (435234h)] 
  4. 00411F91  and         eax,1 
  5. 00411F94  jne         Singleton::GetInstance+0B4h (411FC4h) 
  6. 00411F96  mov         eax,dword ptr [$S1 (435234h)] 
  7. 00411F9B  or          eax,1 
  8. 00411F9E  mov         dword ptr [$S1 (435234h)],eax 
  9. 00411FA3  mov         byte ptr [ebp-4],1 
  10. 00411FA7  push        1    
  11. 00411FA9  mov         ecx,offset inst (435230h) 
  12. 00411FAE  call        Singleton::Singleton (411799h) 
  13. 00411FB3  push        offset `Singleton::GetInstance'::`2'::`dynamic atexit destructor for 'inst'' (42D370h) 
  14. 00411FB8  call        @ILT+480(_atexit) (4111E5h) 
  15. 00411FBD  add         esp,4 
  16. 00411FC0  mov         byte ptr [ebp-4],0 
  17.     return &inst;
  18. 00411FC4  mov         dword ptr [ebp-0E0h],offset inst (435230h) 
  19. 00411FCE  mov         dword ptr [ebp-4],0FFFFFFFFh 
  20. 00411FD5  lea         ecx,[ebp-14h] 
  21. 00411FD8  call        Lock::~Lock (41178Fh) 
  22. 00411FDD  mov         eax,dword ptr [ebp-0E0h] 

我们debug这个代码一下,在断点执行到static Singleton inst(1);的时候看到了这样的汇编语句。汇编语句中括号里面的数值是debug时候的地址。可以看到那个JNE,当条件满足的时候可以跳转到411FC4h,也就是   return &inst; 的位置,如果条件不满足就依次执行构造函数和atexit的设置。简单点的说就是,这里的inst是在程序第一次执行到这条语句的时候做初始化的。而不是main函数之前,loading阶段的。这个可能是很常见的问题还是让自己小小的吃惊了一把。
既有此,想到了另一个形式变量, 如果我在这个函数里面加入一个static int temp = 1;会怎么样呢?这个是在什么时候分配呢?说干就干,这时候我们看到的汇编语句没有任何的变化。(只是显示这样一条C++的语句)。所以这一类的变量的初始化可以说和刚才的顺序是不同的。所以原书中对局部静态变量有了精彩的论述

int Fun()
{
       static int x = 100;
       return ++x;
}
In this case, x is initialized before any code in the program is executed, most likely at load time. For all that Fun can tell when first called, x has been 100 since time immemorial. In contrast, when the initializer is not a compile-time constant, or the static variable is an object with a constructor, the variable is initialized at runtime during the first pass through its definition.
也就是说,局部静态变量如果是基本数据类型,而且赋值语句的右边是编译期常量的话,这个局部变量的初始化实在程序加载期间就完成的。但是如果是那些类的对象(有构造函数)的局部静态变量就是在第一次执行此语句的时候完成初始化的,当然这里还包括基本数据类型的赋值语句右侧是变量的情况。
举个例子有这样的函数
  1. int Func(int x)
  2. {
  3.     static int temp = x*x;
  4. }
可以预见的是这样的temp的初始化是在一次这个函数被调用的时候发生的,不然的话也确实没有办法提前初始化他。
有了以上的论述在发现,确实这样一个Mutex还是有存在的必要性的:)




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值