单例模式是指一个类只能创建一个类对象,本文从第一种单例模式的写法开始介绍,后一种单例模式均是对前一种单例模式可能出现的问题的改进,写法大同小异,读者可跟随文章一起分析。
第一种单例模式
#include<iostream>
using namespace std;
class Clog {
private:
static Clog* ptr;
Clog() = default;
public:
//唯一的创建类的接口
static Clog* createObject(){
if(ptr==nullptr)
ptr=new Clog();
return ptr;
}
};
Clog* Clog::ptr = nullptr;
int main()
{
Clog* p = Clog::createObject();
Clog* p1 = Clog::createObject();
delete p;
delete p1;
//指针接收创建这个唯一的类就是需要手动释放资源,容易引起线程安全问题
}
分析
1)将构造函数声明为私有,而暴露一个createObject()函数创造类对象。
2)将createObject()类对象声明为static,方便我们直接用类名调用该函数,而不必陷入“调用函数应该先创建对象,而创建对象需要调用该函数的这种鸡生蛋,蛋生鸡” 问题。
3)现在需要一个Clog类的指针作为createObject()函数的返回值,而只有静态成员变量才能不用对象就可以调用,而且静态函数内部只能用静态成员变量,所以在类中声明一个静态的Clog指针。
4)在main函数中直接调用Clog类中的createObject方法,会返回一个Clog类对象的指针=Clog::ptr,是Clog类中的静态成员变量,所以不论在main函数中调用多少次,返回的都是唯一的那一个Clog类中的静态成员变量ptr的值。
5)从此我们想要在程序的任何地方使用该单例对象都可以直接调用Clog类中的createObject方法返回这个对象供我们操作。也就是说实现了单例模式,单例模式有什么用呢?比如说我们编程序的时候想要记录我们的日志,那么就可以用这个唯一的单例模式的类对象进行记录。
该方法的不足之处
createObject()函数返回的是Clog*类型new出来的堆对象,我们需要注意内存释放的问题。容易引起线程安全性问题。
这里说明一个解决线程安全性的解法:
#include <iostream>
#include <mutex>
using