【C++设计模式】单例模式(Singleton)
·
系列文章目录
单例模式(Singleton)
单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问该实例。
说人话就是,随便哪个源文件包含了单例类的头文件,他都能在任意位置访问到同一个实例。
1.实现要点
- 私有化构造函数:禁止外部通过构造函数创建实例。
- 提供一个静态方法:用于获取唯一实例,返回类的唯一实例。
2.优缺点
优点:
- 控制实例数量:确保一个类只有一个实例,节省系统资源。
- 全局访问:提供一个全局访问点,方便访问实例。
- 延迟初始化:可以实现延迟初始化,优化系统性能。
缺点:
- 全局状态:单例模式引入全局状态,可能导致代码难以理解和维护,但问题不大。
- 并发问题:在多线程环境下实现单例模式需要考虑线程安全问题,增加了实现的复杂性。
- 扩展性差:单例模式限制了类的扩展性,难以进行子类化。
3.实现方式
3.1基础单例模式
最基础的单例模式
优点:实现简单,适用于单线程。
缺点:可能会因为多个线程同时运行到创建实例,导致同时创建多个实例,线程不安全。
// Singleton.h
class Singleton {
public:
static Singleton* getInstance();
void add();
// 禁止拷贝构造和赋值操作, 放在public里是为了编译时如果报错展示的信息更加详细
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
private:
// 私有构造函数
Singleton() {}
~Singleton() {}
static Singleton* m_instance;
int m_value = 0;
};
// Singleton.cpp
#include <iostream>
#include "Singleton.h"
Singleton* Singleton::m_instance = nullptr; // 静态成员变量初始化
static Singleton::Singleton* getInstance() {
if (m_instance == nullptr) {
m_instance = new Singleton();
}
return m_instance;
}
void Singleton::add() {
std::cout << ++m_value << std::endl;
}
// any.cpp
#inlcude "Singleton.h"
void doubleAdd(){
Singleton::getInstance()->add();
Singleton::getInstance()->add();
}
// main.cpp
#inlcude "Singleton.h"
int main() {
Singleton* ins = Singleton::getInstance();
ins->add();
doubleAdd();
}
运行结果为:
1
2
3
3.2双重检查锁单例模式
很明显基础单例模式并不满足线程安全性,为了使单例模式的实现线程安全,引入双重检查锁。
在普通单例的基础上增加一个锁变量,并在获取单例时增加双重检查。
优点:线程安全,不需要每次调用都消耗锁资源,性能高
缺点:无
// Singleton.h
#include <mutex>
class Singleton {
public:
static Singleton* getInstance();
void add();
// 禁止拷贝构造和赋值操作, 放在public里是为了编译时如果报错展示的信息更加详细
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
private:
// 私有构造函数
Singleton() {}
~Singleton() {}
static Singleton* m_instance;
static std::mutex m_mtx;
int m_value = 0;
};
// Singleton.cpp
#include <iostream>
#include "Singleton.h"
Singleton* Singleton::m_instance = nullptr; // 静态成员变量初始化
std::mutex Singleton::m_mtx;
static Singleton::Singleton* getInstance() {
if (m_instance == nullptr) {
std::lock_guard<std::mutex> lock(m_mtx);
if (m_instance == nullptr) { // 防止上锁前已经被其他线程实例化, 再次检查单例
m_instance = new Singleton();
}
}
return m_instance;
}
void Singleton::add() {
std::cout << ++m_value << std::endl;
}
// any.cpp
#inlcude "Singleton.h"
void doubleAdd(){
Singleton::getInstance()->add();
Singleton::getInstance()->add();
}
// main.cpp
#inlcude "Singleton.h"
int main() {
Singleton* ins = Singleton::getInstance();
ins->add();
doubleAdd();
}
3.3静态局部单例模式
单例模式的实现线程安全化的另一种方法,是使用静态局部变量。
相较于以上两种方法,无需在类内额外设置静态单例变量和锁变量。
优点:线程安全(C++11标准保证),无需静态成员变量初始化
缺点:无法传递参数给单例实例
// Singleton.h
#include <mutex>
class Singleton {
public:
static Singleton* getInstance();
void add();
// 禁止拷贝构造和赋值操作, 放在public里是为了编译时如果报错展示的信息更加详细
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
private:
// 私有构造函数
Singleton() {}
~Singleton() {}
int m_value = 0;
};
// Singleton.cpp
#include <iostream>
#include "Singleton.h"
static Singleton::Singleton* getInstance() {
static Singleton instance; // C++11标准内部保证了静态局部变量的线程安全性
return m_instance;
}
void Singleton::add() {
std::cout << ++m_value << std::endl;
}
// any.cpp
#inlcude "Singleton.h"
void doubleAdd(){
Singleton::getInstance()->add();
Singleton::getInstance()->add();
}
// main.cpp
#inlcude "Singleton.h"
int main() {
Singleton* ins = Singleton::getInstance();
ins->add();
doubleAdd();
}
更多推荐


所有评论(0)