1.什么是单例
单,就是单个的意思,例,就是实例化。所谓单例模式,指的就是程序运行期间,在全局范围内,有且只有一个类的实例化存在。它其实是一种设计思想,和语言没有关系。只要按照这种设计思想,哪种语言都可以实现自己的单例模式。
单例模式用的最多的场景就是工具类,节省资源,全局调用。
而为了保证只有一个实例存在,在设计单例时候,就要将类的构造函数私有化,防止外部创建。同时将类的拷贝构造函数和赋值操作符删除,防止复制和赋值。
单例模式的实现方式有三种。C++11之前,主要通过饿汉式或懒汉式实现,C++11之后,通过静态局部变量实现。静态局部变量这种方式,既简洁又高效。
2.饿汉式
饿汉式是通过类的静态成员变量实现的。因为静态成员变量的初始化,是在main函数加载前完成的,所以它天然是线程安全的。
代码举例如下:
头文件:EagerSingleton.h
cpp
//EagerSingleton.h
#pragma once
#include <iostream>
using namespace std;
class EagerSingleton
{
public:
static EagerSingleton& getInstance() {
return instance;
}
void doSomething() {
cout << "EagerSingleton 做事..." << endl;
}
private:
// 私有构造函数
EagerSingleton() { cout << "EagerSingleton 构造函数" << endl; }
// 拷贝构造和赋值操作符删除,防止复制
EagerSingleton(const EagerSingleton&) = delete;
EagerSingleton& operator=(const EagerSingleton&) = delete;
// 静态实例在类外定义,程序启动时即初始化
static EagerSingleton instance;
};
源文件:EagerSingleton.cpp
cpp
#include "EagerSingleton.h"
EagerSingleton EagerSingleton::instance;
调用方式:
cpp
EagerSingleton& s1 = EagerSingleton::getInstance()
3.懒汉式
懒汉式又可分为两种,一种是简单版本,一种是双重检测+锁版本。他俩唯一区别就是第一个不是线程安全,第二个是线程安全的。
简单版本代码举例
头文件:LazySingleton.h
cpp
#pragma once
#include <iostream>
using namespace std;
class LazySingleton
{
public:
static LazySingleton* getInstance() {
if (instance == nullptr) { // 多线程下可能同时进入
instance = new LazySingleton();
}
return instance;
}
void doSomething() {
cout << "LazySingleton 做事..." << endl;
}
private:
// 私有构造函数
LazySingleton() { cout << "LazySingleton 构造函数" << endl; }
// 拷贝构造和赋值操作符删除,防止复制
LazySingleton(const LazySingleton&) = delete;
LazySingleton& operator=(const LazySingleton&) = delete;
// 静态实例在类外定义,程序启动时即初始化
static LazySingleton* instance;
};
源文件:LazySingleton.cpp
cpp
#include "LazySingleton.h"
LazySingleton* LazySingleton::instance = nullptr;
双重检测+锁版本代码举例
头文件:LazySingletonDCL.h
cpp
#pragma once
#include <iostream>
#include <mutex>
using namespace std;
class LazySingletonDCL
{
public:
static LazySingletonDCL* getInstance() {
// 第一层判断:避免每次加锁损耗性能
if (instance == nullptr) {
lock_guard<mutex> lock(mtx);
// 第二层判断:防止多线程等待锁后重复创建
if (instance == nullptr) {
instance = new LazySingletonDCL();
}
}
return instance;
}
void doSomething() {
cout << "LazySingletonDCL 做事..." << endl;
}
private:
// 私有构造函数
LazySingletonDCL() { cout << "LazySingletonDCL 构造函数" << endl; }
// 拷贝构造和赋值操作符删除,防止复制
LazySingletonDCL(const LazySingletonDCL&) = delete;
LazySingletonDCL& operator=(const LazySingletonDCL&) = delete;
// 静态实例在类外定义,程序启动时即初始化
static LazySingletonDCL* instance;
static mutex mtx;
};
源文件:LazySingletonDCL.cpp
cpp
#include "LazySingletonDCL.h"
LazySingletonDCL* LazySingletonDCL::instance = nullptr;
mutex LazySingletonDCL::mtx;
调用方式
cpp
LazySingleton* s1 = LazySingleton::getInstance();
4.静态局部变量方式
这种方式是C++11后才能使用,是目前单例的最优解。
代码举例如下:
头文件:SingletonMeyer.h
cpp
#pragma once
#include <iostream>
using namespace std;
class SingletonMeyer
{
public:
static SingletonMeyer& getInstance() {
// 第一次调用才创建,线程安全
static SingletonMeyer instance;
return instance;
}
void doSomething() {
cout << "SingletonMeyer 做事..." << endl;
}
private:
// 私有构造函数
SingletonMeyer() { cout << "SingletonMeyer 构造函数" << endl; }
// 拷贝构造和赋值操作符删除,防止复制
SingletonMeyer(const SingletonMeyer&) = delete;
SingletonMeyer& operator=(const SingletonMeyer&) = delete;
};
源文件:SingletonMeyer.cpp
cpp
#include "SingletonMeyer.h"
//相关函数也可以在头文件中声明,在这里实现。
调用方式
cpp
SingletonMeyer& ins = SingletonMeyer::getInstance();
ins.doSomething();