您的位置:首页 > 编程语言 > C语言/C++

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

2008-12-09 11:42 351 查看
#include <iostream>
using namespace std;
 
/* Place holder for thread synchronization mutex */
class Mutex
{   /* placeholder for code to create, use, and free a mutex */
};
 
/* Place holder for thread synchronization lock */
class Lock
{   public:
        Lock(Mutex& m) : mutex(m) { /* placeholder code to acquire the mutex */ }
        ~Lock() { /* placeholder code to release the mutex */ }
    private:
        Mutex & mutex;
};
 
class Singleton
{   public:
        static Singleton* GetInstance();
        int a;
 
    private:
        Singleton(int _a) : a(_a) { cout << "In Ctor" << endl; }
        ~Singleton() { cout << "In Dtor" << endl; }
 
        static Mutex mutex;
 
        // Not defined, to prevent copying
        Singleton(const Singleton& );
        Singleton& operator =(const Singleton& other);
};
 
Mutex Singleton::mutex;
 
Singleton* Singleton::GetInstance()
{
    Lock lock(mutex);
 
    cout << "Get Inst" << endl;
 
    // Initialized during first access
    static Singleton inst(1);
 
    return &inst;
}
 
int main()
{
    Singleton* singleton = Singleton::GetInstance();
    cout << "The value of the singleton: " << singleton->a << endl;
    return 0;
}
 在wikipedia上看到Singleton pattern的描述时偶然看到了一个Singleton的实现,局部的静态变量我们看到很多了。但是这里的mutex让人感觉有点不必要。 感觉static Singleton inst(1);这个语句应该在loading的阶段就已经执行了,所以不存在所谓多线程的问题。但是实际上看了之后还是大吃一惊的。
    // Initialized during first access
    static Singleton inst(1);
00411F8C  mov         eax,dword ptr [$S1 (435234h)] 
00411F91  and         eax,1 
00411F94  jne         Singleton::GetInstance+0B4h (411FC4h) 
00411F96  mov         eax,dword ptr [$S1 (435234h)] 
00411F9B  or          eax,1 
00411F9E  mov         dword ptr [$S1 (435234h)],eax 
00411FA3  mov         byte ptr [ebp-4],1 
00411FA7  push        1    
00411FA9  mov         ecx,offset inst (435230h) 
00411FAE  call        Singleton::Singleton (411799h) 
00411FB3  push        offset `Singleton::GetInstance'::`2'::`dynamic atexit destructor for 'inst'' (42D370h) 
00411FB8  call        @ILT+480(_atexit) (4111E5h) 
00411FBD  add         esp,4 
00411FC0  mov         byte ptr [ebp-4],0 

    return &inst;
00411FC4  mov         dword ptr [ebp-0E0h],offset inst (435230h) 
00411FCE  mov         dword ptr [ebp-4],0FFFFFFFFh 
00411FD5  lea         ecx,[ebp-14h] 
00411FD8  call        Lock::~Lock (41178Fh) 
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.也就是说,局部静态变量如果是基本数据类型,而且赋值语句的右边是编译期常量的话,这个局部变量的初始化实在程序加载期间就完成的。但是如果是那些类的对象(有构造函数)的局部静态变量就是在第一次执行此语句的时候完成初始化的,当然这里还包括基本数据类型的赋值语句右侧是变量的情况。举个例子有这样的函数int Func(int x)
{
    static int temp = x*x;
}
可以预见的是这样的temp的初始化是在一次这个函数被调用的时候发生的,不然的话也确实没有办法提前初始化他。有了以上的论述在发现,确实这样一个Mutex还是有存在的必要性的:)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: