单例模式
单例模式设计的类只能实例化一个对象,但是这个对象可以在全局使用。实现方法:类自身保存自己的实例,提供访问该实例的方法。
实现方法:
- 声明自己的静态私有对象
- 将创造对象的构造函数设置为私有,那么外界就无法创建对象了
- 提供公有的访问对象的静态函数
预备知识:静态成员和静态变量:
- 将成员或函数声明为静态的,那么这些成员和变量在类的所有对象之间是共享的,相当于类内全局变量。其中一个用途用来记录该类实例了多少对象。
- 静态成员函数是没有this指针的,C++中调用方式 <类名>::<成员>。
- 一般类在实例化对象的时候会为类成员分配内存空间。但是静态成员函数和静态成员变量在实例化对象的时候不会被分配内存空间,因为在对象创建之前(编译阶段)就已经被分配了内存。
- 静态成员变量不能在类内初始化,这样可以防止每个对象都包含静态成员
预备知识:互斥锁
- 头文件#include《mutex》
- 实例化:std::mutex mtx
- 上锁:mtx.lock(), mtx.try_lock();解锁mtx.unlock()
单线程单例模式
#include<iostream>
//单例模式类的定义
class Singleton {
private:
Singleton() {};
~Singleton() {};
public:
static Singleton* GetSingletonObject() { //提供单例的访问接口
if (singleton_object == nullptr) { //第一次调用时,分配内存空间
singleton_object = new Singleton();
}
return singleton_object;
}
private:
//static Singleton *singleton_object = nullptr; //错误,静态成员变量不能在类内初始化
static Singleton *singleton_object; //静态成员变量,就是单例模式中共享的实例
};
/**********************************客户端调用,用于验证*****************************/
Singleton* Singleton::singleton_object = nullptr; //在类外初始化静态成员变量
int main() {
Singleton *s1 = Singleton::GetSingletonObject();
Singleton *s2 = Singleton::GetSingletonObject();
if (s1 == s2) {
std::cout << "是同一个对象" << std::endl;
}
return 0;
}
由于没有释放类成员singleton_object的内存,会造成内存泄露,下面博客提出了解决办法:
C++中的单例模式
其中的《effective C++》实现的方式中,local static实现方式是指: 将每个 non-local static对象搬到自己的专属函数内,这些函数返回一个reference指向它所指向的对象。这个手法的基础在于:C++保证,在“该函数被调用期间”“首次遇到该对象”时进行初始化。
多线程单例模式
上述单线程单例模式在多个线程同时检测到singleton_object == nullptr时,会创建多个single_object;所以需要进行上锁
public:
static Singleton* GetSingletonObject() { //提供单例的访问接口
mtx.lock();
if (singleton_object == nullptr) { //第一次调用时,分配内存空间
singleton_object = new Singleton();
}
mtx.unlock();
return singleton_object;
}
这里每次运行GetSingletonObject的时候都要进行互斥锁的操作,很影响效率。所以人们发明了双锁,
public:
static Singleton* GetSingletonObject() { //提供单例的访问接口
if (singleton_object == nullptr) {
mtx.lock();
if (singleton_object == nullptr) { //第一次调用时,分配内存空间
singleton_object = new Singleton();
}
mtx.unlock();
}
return singleton_object;
}
参考博客:C++程序员们,快来写最简洁的单例模式吧
参考书籍《大话设计模式》
参考博客:C++11并发指南三(std::mutex详解)