单例模式
一个类中只产生一个对象,并提供一个外部访问点,被程序全员共享,简化了在复杂环境下的配置管理,这种模式被成为单例模式。
特征:
- 单例类最多只能有一个实例;
- 单例类必须自己创建自己唯一的实例;
- 单例类必须给所有其他的对象提供这一实例。
优点:1.内存中该类只实例化了一个对象,减少了内存的消耗;2.避免资源的重复占用
缺点:单例类的话,不能被继承,因为它的构造函数那些东西都是私有(private)的;
一、饿汉模式
不管用不用,在程序开始就加载,会导致程序启动慢,且如果有多个单例类对象实例启动顺序不确定。
线程安全,一共只生成一个静态对象。
饿汉模式虽好,但其存在隐藏的问题,在于非静态对象(函数外的static对象)在不同编译单元中的初始化顺序是未定义的。如果在初始化完成之前调用 getInstance() 方法会返回一个未定义的实例。
将单例类的唯一对象实例,通过一个静态成员变量来实现,加载进程时即完成创建,无论用或不用该单例对象都一直存在。
当这个对象特别大的时候,无论你用不用该对象,在使用程序开始的那一课开始,对象已经存在,会造成巨大的内存浪费。
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
41
| // .h
class HungerSingleton {
private:
static HungerSingleton instance; //静态对象
HungerSingleton();
~HungerSingleton();
//防拷贝
HungerSingleton(const HungerSingleton&) = delete;
HungerSingleton& operator=(const HungerSingleton&) = delete;
public:
static HungerSingleton* GetInstance();
void func(int n)
{
std::cout << n << std::endl;
Sleep(n);
}
};
// .cpp
#include"HungerSingleton.h"
HungerSingleton HungerSingleton::instance; //类外初始化
HungerSingleton* HungerSingleton::GetInstance() {
return &instance;
}
HungerSingleton::HungerSingleton() {
std::cout << "HungerSingleton构造函数" << std::endl;
}
HungerSingleton::~HungerSingleton() {
std::cout << "HungerSingleton析构函数" << std::endl;
}
// main
int main() { //HungerSingleton构造函数
auto hung = HungerSingleton::GetInstance();
hung->func(5); //5
hung->func(3); //3
return 0; //HungerSingleton析构函数
}
|
二、懒汉模式
等到用的的时候程序再创建实例对象
第一次使用实例对象时,创建对象,进程启动无负载。多个单例实例启动顺序自由控制
非线程安全,当多进程同时创建时,会发生争抢,需要加锁和双重检验
无内存管理,会发生内存泄漏
1.简易版
为保证多线程下的线程安全,使用双重检验,对单例对象加锁保证竞争不会重复创建
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
| /*
* LazySingleton.h
*/
#pragma once
#ifndef _LAZYSINGLETON_H_
#define _LAZYSINGLETON_H_
#include <iostream>
#include <mutex>
class LazySingleton {
private:
static LazySingleton* instance; //指向对象的指针
LazySingleton();
~LazySingleton();
static std::mutex m_mtx; //互斥锁
public:
static LazySingleton* GetInstance();
};
#endif // !_LAZYSINGLETON_H_
/*
* LazySingleton.cpp
*/
#include"LazySingleton.h"
LazySingleton* LazySingleton::instance = nullptr; //初始化为空指针
std::mutex LazySingleton::m_mtx;
LazySingleton::LazySingleton() {
std::cout << "LazySingleton构造函数" << std::endl;
}
LazySingleton::~LazySingleton() {
std::cout << "LazySingleton析构函数" << std::endl;
}
LazySingleton* LazySingleton::GetInstance() {
if (instance == nullptr) {
//加锁
std::lock_guard<std::mutex>lock(m_mtx); //类模板,只提供构造函数和析构函数,在析构时自动解锁,可以使用{}来限制使用范围
if (instance == nullptr) { //双重检验
instance = new LazySingleton();
}
}
return instance;
}
void func(int n)
{
cout << LazySingleton::GetInstance() << endl;
}
int main() {
thread t1(func, 10);
thread t2(func, 10);
t1.join(); //进程1运行:创建LazySingleton 单例对象地址不变
t2.join(); //进程2运行:不用创建
cout << LazySingleton::GetInstance() << endl; //不用创建
cout << LazySingleton::GetInstance() << endl; //不用创建
//懒汉模式不会自动析构
return 0;
}
|