单例模式分懒汉模式和饿汉模式。本文对饿汉子模式中的一些细节进行简要说明。
1、单例类的实例化可以采用堆也可以采用全局区,分别对应指针对象和普通对象。指针对象的地址需要使用static 修饰,所以也是保存在全局区,指针对象是通过new出来的,所以对应类的大小内存是在堆上开辟的。那是使用指针对象还是普通对象呢?
我建议使用普通对象,有两个原因。一是单例类的实例化,一般不释放,而堆却是动态的意思,所以没必要将一般不释放的内存在动态的堆上开辟。二是程序结束时,系统会释放所有的全局变量,包括这里的static普通对象,这样就可以自动调用析构函数处理其它需要关闭文件之类的操作,可以参考后文。
static成员均需要类内声明,类外cpp文件初始化。两者写法如下。
.h文件如下:
class CReject{
public:
static CReject* GetInstance()
{
return spInst;
或
return &Inst;
}
private:
static CReject* spInst;
static CReject Inst;
//static EchReject* spInst = new EchReject;//这是错误的
};
.cpp文件如下
CReject* CReject::spInst = new CReject();//或者new CReject;
CReject CReject::Inst;
new CReject() 和new CReject 没有区别。对于系统内置的类型,比如new int和new int()有区别,带括号具有初始化的作用。
2、保证单例
如何保证单例?先看看不保证单例的设计:
class CReject{
public:
static CReject* GetInstance()
{
return spInst;
}
void PrintValue(){
qDebug()<<"PrintValue"<<mValue;}
void SetValue(int v){
mValue=v;}
public:
CReject(const CReject&e) //拷贝构造函数
{
qDebug()<<"重写拷贝构造函数";
mValue = e.mValue;
}
CReject& operator=(const CReject&e) //赋值函数
{
qDebug()<<"重写赋值函数";
return *this;
}
public:
CReject(){
qDebug()<<"普通构造函数";}
~CReject(){
qDebug()<<"析构函数"<<mValue;}
private:
static CReject* spInst;
int mValue;
};
CReject* CReject::spInst = new CReject