比较几种常见的单例模式实现
方法一:
#include<iostream>
using namespace std;
class Singleton
{
private:
Singleton():Data(0) //构造函数声明为私有
{
}
static Singleton * Instance;
public:
static Singleton & GetInstance();
int Data;//用于测试
};
Singleton * Singleton::Instance=NULL;
Singleton & Singleton::GetInstance()
{
if(Instance == NULL) //判断是否实例已经存在
{
Instance = new Singleton();
}
return *Instance;
}
int main(void)
{
Singleton& singletonObj1=Singleton::GetInstance();
cout<<singletonObj1.Data<<endl;
singletonObj1.Data=1;
cout<<singletonObj1.Data<<endl;
Singleton& singletonObj2=Singleton::GetInstance();
cout<<singletonObj2.Data<<endl;//通过观测此次输出的结果可知,singletonObj1与singletonObj2是同一对象
singletonObj2.Data=2;
cout<<singletonObj2.Data<<endl;
return 0;
}
方法一是最基本的实现了单例模式。
方法二:
#include<iostream>
using namespace std;
class Singleton
{
private:
Singleton():Data(0) //构造函数声明为私有
{
}
static Singleton * Instance;
public:
static Singleton & GetInstance();
int Data;//用于测试
};
Singleton * Singleton::Instance=NULL;
Singleton & Singleton::GetInstance()
{
if(Instance == NULL) //判断是否实例已经存在
{
lock(); //需要另外实现
if (Instance==NULL)
{
Instance = new Singleton();
}
unlock(); //需要另外实现
}
return *Instance;
}
int main(void)
{
Singleton& singletonObj1=Singleton::GetInstance();
cout<<singletonObj1.Data<<endl;
singletonObj1.Data=1;
cout<<singletonObj1.Data<<endl;
Singleton& singletonObj2=Singleton::GetInstance();
cout<<singletonObj2.Data<<endl;//通过观测此次输出的结果可知,singletonObj1与singletonObj2是同一对象
singletonObj2.Data=2;
cout<<singletonObj2.Data<<endl;
return 0;
}
方法二相对于方法一,增加了多线程安全
方法三:
#include<iostream>
using namespace std;
class Singleton
{
private:
Singleton():Data(0) //构造函数声明为私有
{
}
static Singleton * Instance;
public:
static Singleton & GetInstance();
int Data;//用于测试
};
Singleton * Singleton::Instance=new Singleton();
Singleton & Singleton::GetInstance()
{
return *Instance;
}
int main(void)
{
Singleton& singletonObj1=Singleton::GetInstance();
cout<<singletonObj1.Data<<endl;
singletonObj1.Data=1;
cout<<singletonObj1.Data<<endl;
Singleton& singletonObj2=Singleton::GetInstance();
cout<<singletonObj2.Data<<endl;//通过观测此次输出的结果可知,singletonObj1与singletonObj2是同一对象
singletonObj2.Data=2;
cout<<singletonObj2.Data<<endl;
return 0;
}
方法三的实例在程序启动时就已经创建,因此在每次获取的时候就不需要进行任何的判断。
方法四:
#include<iostream>
using namespace std;
class Singleton
{
private:
Singleton():Data(0) //构造函数声明为私有
{
}
// Singleton(const Singleton&);
// Singleton& operator=(const Singleton&);
public:
static Singleton & GetInstance();
int Data;//用于测试
};
Singleton & Singleton::GetInstance()
{
static Singleton Instance;
return Instance;
}
int main(void)
{
Singleton& singletonObj1=Singleton::GetInstance();
cout<<singletonObj1.Data<<endl;
singletonObj1.Data=1;
cout<<singletonObj1.Data<<endl;
Singleton& singletonObj2=Singleton::GetInstance();
cout<<singletonObj2.Data<<endl;//通过观测此次输出的结果可知,singletonObj1与singletonObj2是同一对象
singletonObj2.Data=2;
cout<<singletonObj2.Data<<endl;
return 0;
}
方法四将实例指定为静态局部变量,它是在第一次调用Singleton::GetInstance()时创建。其为局部静态变量,不是new出来的,在程序结束时能自动销毁,不用delete。但是其存在的一个问题就是,如果不是用引用调用此静态函数,而是Singleton singletonObj3=Singleton::GetInstance(),此句是调用复制构造函数,用GetInstance()返回的静态变量的值对singletonObj3对象初始化(此时在内存中有两个对象,静态对象和singletonObj3),为了防止此问题出现,应该也显示声明复制构造函数为私有。还有一个问题就是自我赋值,singletonObj1=singletonObj2,两者是同一个东西,为了防止此情况出现,我们可以在重载赋值操作中判断是否为同一个对象,但是单例模式中永远只有一个对象,那么我们干脆就显示声明赋值操作为私有既可。
即在类中把那两句注释消去,其实就是在编译中禁止了以上所说的两种操作,如果使用了,编译器会报错。
可以看出方法一、二、三都存在缺少delete的问题。
正常项目中,全局实例只有一个,在程序结束时,系统会释放内存资源,所以没有delete的问题并不大,不会发生内存泄露。但是在对象有 操作文件 或者 连接数据库 时,程序关闭时不会立即关闭资源,就需要在程序关闭前,手动释放资源。由于都是静态变量,因此不能使用类的析构函数对它进行销毁,有些人就想出了使用嵌套类专门处理释放资源。在方法一中加入嵌套类Garbo
class Singleton
{
private:
Singleton():Data(0) //构造函数声明为私有
{
}
static Singleton * Instance;
public:
static Singleton & GetInstance();
int Data;//用于测试
class Garbo //它的唯一工作就是在析构函数中删除CSingleton的实例
{
public:
~Garbo()
{
if( Singleton::Instance )
delete Singleton::Instance;
}
};
static Garbo Garbo; //定义一个静态成员,程序结束时,系统会自动调用它的析构函数
};
Singleton * Singleton::Instance=NULL;
Singleton & Singleton::GetInstance()
{
if(Instance == NULL) //判断是否实例已经存在
{
Instance = new Singleton();
}
return *Instance;
}
需要更详细的内容可以参考 果冻想
http://www.jellythink.com/archives/82