面向对象设计模式之单例模式


单例是最简单的一种设计模式,其只有一个类定义,整个系统运行中,该类只允许存在一个实例。

单例模式不能让外部创建该类实例,只能自己类内部创建唯一实例,所以需要将构造函数私有化。

单例通常有两种实现方式:饿汉模式和懒汉模式。

恶汉模式:在系统初始化时创建实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//singleton.h
class Singleton {
public:
static Singleton* getInstance();
~Singleton() {
delete _instance;
}
protected:
Singleton();
private:
static Singleton* _instance;
};
//singleton.cpp
Singleton *Singleton::_instance = new Singleton();
Singleton* Singleton::getInstance() {
return _instance;
}

恶汉模式将单例对象设置为静态对象,在程序启动时即可完成对象初始化,所以是线程安全的。

懒汉模式:实例在第一次被调用时创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//singleton.h
class Singleton {
public:
static Singleton* getInstance();
~Singleton() {
if( (_instance != NULL)
delete _instance;
}
protected:
Singleton();
private:
static Singleton* _instance;
};
//singleton.cpp
Singleton *Singleton::_instance = NULL;
Singleton* Singleton::getInstance() {
if( _instance == NULL) {
_instance = new Singleton();
}
return _instance;
}

懒汉模式在多线程程序中是非线程安全的,可能会创造多个实例而造成内存泄漏。所以需要加锁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//singleton.h
class Lock {
private:
mutex& mtex;
public:
Lock(mutex& m) : mtex(m) {
mtex.Lock();
}
~Lock() {
mtex.Unlock();
}
};
class Singleton {
public:
static Singleton* getInstance();
~Singleton() {
if( (_instance != NULL)
delete _instance;
}
protected:
Singleton();
private:
static Singleton* _instance;
static mutex m;
};
//singleton.cpp
Singleton *Singleton::_instance = NULL;
Singleton* Singleton::getInstance() {
Lock lock(m);
if( _instance == NULL) {
_instance = new Singleton();
}
return _instance;
}

但是保证线程安全,其实只需要在第一次调用时加锁,_instance赋值后,每次加锁就成了浪费的开销。所以为了解决这个问题,通常采用双重判断。

1
2
3
4
5
6
7
8
9
Singleton* Singleton::getInstance() {
if( _instance == NULL) {
Lock lock(m);
if( _instance == NULL) {
_instance = new Singleton();
}
}
return _instance;
}