单例模式C++实现 - STEMHA's Blog

单例模式C++实现

单例模式

singleton pattern
purpose:使得一个类只能有一个实例,并提供一个全局访问的位置
probliem:遇到实例的频繁创建和销毁时,效率低
solution:创建时候检测实例是否存在
key code:构造函数是私有的

如何选择懒汉和饿汉模式:

特点与选择:
懒汉:在访问量较小时,采用懒汉实现。这是以时间换空间。
饿汉:由于要进行线程同步,所以在访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,可以实现更好的性能。这是以空间换时间。

懒汉式单例模式代码(线程不安全)

顾名思义,该模式只在你需要对象时才会生成单例对象(意思是太懒了,懒汉不到万不得已就不会去实例化类)
缺点:

  • 懒汉式是以时间换空间的方式。(在getInstance中new instance然后返回)
  • 适用于单线程的环境!
  • 不是线程安全的!
    • 它不是线程安全的。假设当前有N个线程同时调用getInstance()方法,由于当前还没有对象生成,所以一部分同时都进入步骤 2,那么就会由多个线程创建多个多个singleton对象。
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
35
36
37
38
39
懒汉式单例模式
- 私有静态指针,指向单例
- 私有构造函数
- 公有获取实例的静态函数
# include <iostream>
using namespace std;

class singleton{
public:
static singleton *getinstance()
{
if (instance == NULL) 步骤 1
{
instance = new singleton(); 步骤 2
return instance;
}
else
{
cout << "instance has already initialized" << endl;
return instance;
}
}
private:
static singleton * instance ;
singleton()
{
cout << "instance initialized" << endl;
}
};
singleton * singleton::instance = NULL;

int main()
{
singleton * singleton1 = singleton::getinstance();
singleton * singleton2 = singleton::getinstance();
}
//输出
//instance initialized
//instance has already initialized

饿汉式单例模式代码(线程安全)

顾名思义,该模式在类被加载时就会实例化一个对象。(意思是有就吃,有加载个类的话,饿汉就直接在类里面建立)

  • 饿汉式是以空间换时间的方式。(在静态区初始化instance,然后通过getInstance返回)
  • 该模式能简单快速的创建一个单例对象,而且是线程安全的(只在类加载时才会初始化,以后都不会)。
  • 缺点,就是不管你要不要都会直接创建一个对象,会消耗一定的性能(当然很小很小,几乎可以忽略不计,所以这种模式在很多场合十分常用而且十分简单)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# include <iostream>
using namespace std;
class singleton{
public:
static singleton *getinstance(){
return instance;
}

private:
static singleton *instance;
singleton()
{
cout << "instance initialized" << endl;
}
};

singleton * singleton::instance = new singleton(); //关键的一步

int main()
{
singleton *singleton1 = singleton::getinstance();
singleton *singleton2 = singleton::getinstance();
}

注意,这个单例在主函数之前就已经加载了,比如下面主函数输出的结果就是instance initialized。

1
2
3
int main(){
return 0;
}

线程安全的懒汉式单例模式代码

加了一个互斥锁

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
35
36
37
38
39
40
# include <iostream>
# include <mutex>
# include <pthread.h>
using namespace std;

class singleton{
public:
static pthread_mutex_t mutex;

static singleton *getinstance()
{
pthread_mutex_lock(&mutex);
if (instance == NULL)
{
instance = new singleton();
return instance;
}
else
{
cout << "instance has already initialized" << endl;
return instance;
}
pthread_mutex_unlock(&mutex);
}
private:
static singleton * instance ;
singleton()
{
pthread_mutex_init(&mutex,NULL); //初始化为一个互斥锁
cout << "instance initialized" << endl;
}
};
singleton * singleton::instance = NULL;
pthread_mutex_t singleton::mutex;

int main()
{
singleton * singleton1 = singleton::getinstance();
singleton * singleton2 = singleton::getinstance();
}

注意:
互斥变量使用特定的数据类型:pthread_mutex_t
线程函数编译时需要添加特殊编译选项:
gcc read.c -lpthread 比如最简单的编译命令,记住要在后加-lpthread选项,
否则会出现undefined reference to ‘pthread_mutex_lock’报错。

参考资料

饿汉式和懒汉式(单例模式详解)
C++ 单例模式(懒汉、饿汉模式)
C++关于锁的总结(一)
windows下std 没有成员 thread、thread not member of std
c++线程中的几种锁

本文许可证

本文遵循 CC BY-NC-SA 4.0(署名 - 非商业性使用 - 相同方式共享) 协议,转载请注明出处,不得用于商业目的。
CC BY-NC-SA 4.0

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×