单例模式
目的:一个类只能创建一个对象
使用场景:
- 需要生成唯一序列的环境
- 需要频繁实例化然后销毁的对象。
- 创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
- 方便资源相互通信的环境
优点:
- 实现了对唯一实例访问的可控
- 对于一些需要频繁创建和销毁的对象来说可以提高系统的性能。
缺点:
- 不适用于变化频繁的对象
- 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出。
- 如果实例化的对象长时间不被利用,系统会认为该对象是垃圾而被回收,这可能会导致对象状态的丢失
实现步骤:
- 将构造函数与析构函数设置为私有方式
- 分别创建静态的创建对象与销毁对象的函数
代码1
#include <iostream>
using namespace std;
class singleton
{
private:
// 将构造函数和析构函数设置为私有的,这样就不可以创建栈对象
// 满足单例模式一个类只能创建一个对象的需求
singleton()
{
cout << "singleton()" << endl;
}
~singleton()
{
cout << "~singleton()" << endl;
}
//静态成员函数不能调用非静态成员,所以将该成员设置为static
static singleton *_pInstance;
public:
//由于需要调用该函数来创建对象,但是又必须先创建对象才能调用该函数,所以
//需要将该函数设置为static,这样就可以通过类名加作用域限定符的方式调用了
static singleton *getInstance()
{
//通过判断,为了只创建一次对象
if (_pInstance == nullptr)
{
_pInstance = new singleton();
}
return _pInstance;
}
static void destroy()
{
if (_pInstance != nullptr)
{
delete _pInstance;
_pInstance = nullptr;
}
}
};
singleton *singleton::_pInstance = nullptr;
int main()
{
singleton *ps1 = singleton::getInstance();
singleton *ps2 = singleton::getInstance();
cout << "ps1 = " << ps1 << endl
<< "ps2 = " << ps2 << endl;
ps1->destroy();
ps2->destroy();
singleton::destroy();
return 0;
}
运行结果:
singleton()
ps1 = 0x55d09ad1fe70
ps2 = 0x55d09ad1fe70
~singleton()
单例的自动释放
若想让对象结束的时候自动释放所持有的资源,可以使用atexit函数来实现
#include <stdlib.h>
int atexit(void (*function)(void));
// atexit - register a function to be called at normal process termination
只需要在创建对象的后面加上该函数。这样就不需要手动释放资源了。
static singleton *getInstance()
{
if (_pInstance == nullptr)
{
_pInstance = new singleton();
atexit(destroy);
}
return _pInstance;
}
线程安全性
对于上述代码在单个线程的时候,是不会出现问题的,但是当多个线程的时候,就会出现线程不安全的问题,上述代码其实就是单例模式的懒汉模式(使用的时候才创建对象)
下面介绍另外一种模式叫做饿汉模式(不管用不用对象,程序启动的时候就创建对象)
代码很简单
将饱汉模式:singleton *singleton::_pInstance = nullptr;
改成
饿汉模式:singleton *singleton::_pInstance = getInstance();
其实对于懒汉模式也可以通过加锁的方式实现线程安全。