前言
单例模式是最常用的设计模式之一, 它可以保证系统中只有一个实例,从而避免频繁的创建和销毁对象,减少系统开销
特点
- 全局只有一个实例,所有模块共享
- 提供一个全局访问的方法:getInstance(), 静态成员函数
- 构造函数私有化
- 内置静自身态成员对象(或指针)
代码实现
#ifndef _SINGLETON_H
#define _SINGLETON_H
class Singleton
{
public:
static Singleton * getInstance()
{
if(m_singleton == nullptr)
{
m_singleton = new Singleton();
}
return m_singleton;
}
private:
Singleton()
{
}
private:
static Singleton *m_singleton;
};
Singleton *Singleton::m_singleton = nullptr;
#endif
注意:
- 构造函数私有化,提供静态函数getInstance()来生成对象
- 内部包含静态成员,且在类外面初始化(且在该类文件中)
存在风险: 线程不安全
当多线程操作时, 有可能会在执行 if(m_singleton == nullptr)语句时,容易由于临界点问题,导致两个对象产生
解决办法:双重锁定
Singleton* getInstance()
{
if (instance == NULL)
{
lock(); //创建静态mutex,使用局部lock即可
if (instance == NULL)
{
instance = new Singleton();
}
unlock();
}
return instance;
}
常用的场景
单例模式常常与工厂模式结合使用,因为工厂只需要创建产品实例就可以了,在多线程的环境下也不会造成任何的冲突,因此只需要一个工厂实例就可以了。
类型
- 懒汉式 : 不到万不得已时不创建对象
- 恶汉式 : 类构造时就创建(静态函数,在程序一开始运行时即创建,使用时直接返回)
特点与选择:
由于要进行线程同步,所以在访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,可以实现更好的性能。这是以空间换时间
在访问量较小时,采用懒汉实现。这是以时间换空间。