C++单例照effective c++上例子是用将构造函数权限设为private或protected的方法,今天看到另一种,就是利用锁,虽然觉得有点耗资源。
class A{
public:
A(){pthread_mutex_lock(&mutex);}
~A(){pthread_mutex_unlock(&mutex);}
static A* Instance(){...}
};
一般方法如下,摘自:http://hi.baidu.com/gaogaf/blog/item/10c5d3c880b7df1c7f3e6f2f.html
==1============================================
1. 最优实现
class CSingleton
{
public:
static CSingleton& GetInstance()
{
static CSingleton theSingleton;
return theSingleton;
}
/* more (non-static) functions here */
private:
CSingleton() // 必须定义, 且为private.
{
}
CSingleton(const CSingleton&); // 不实现.
CSingleton& operator=(const CSingleton&); // 不实现.
~CSingleton() // 可声明为public, 但这里声明为private没有错, 可被调用.
{
}
};
2. 其它实现
class CSingleton:
{
public:
static CSingleton* GetInstance()
{
if (!m_pInstance)
{
m_pInstance = new CSingleton;
}
return m_pInstance;
}
/* more (non-static) functions here */
private:
CSingleton() // 必须定义, 且为private.
{
}
static CSingleton* m_pInstance;
class CGarbo // 它的唯一工作就是在析构函数中删除CSingleton的实例.
{
public:
~CGarbo()
{
if (CSingleton::m_pInstance)
{
delete CSingleton::m_pInstance;
}
}
};
static CGarbo m_garbo; // 定义一个静态成员, 在程序结束时, 系统会调用它的析构函数.
};
CSingleton* CSingleton::m_pInstance = NULL; // 这句必须有.
==2============================================
C++中的单例模式
单例模式很有用,使用单例模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。
但是在程序的开发过程中我们总是遇到一些问题,而这些问题主要集中在单例类的消毁过程中,普通使用的单例模式的类如下:
class Singleton:
{
// 其它成员
public:
static Singleton * GetInstance()
{
if (m_pInstance == NULL)
m_pInstance = new Singleton();
return m_pInstance;
}
private:
Singleton(){};
static Singleton * m_pInstance;
}
可是这个类在什么时候调用它的析构函数呢,我们怎么消毁它。提供一个公用的destroy函数来进行它的消毁吗,这很不美观。最后我就在网上找到了如果下的代码处理了这个问题:
class Singleton:
{
// 其它成员
public:
static Singleton * GetInstance(){...}
private:
Singleton(){};
static Singleton * m_pInstance;
class CGarbo // 它的唯一工作就是在析构函数中删除Singleton的实例
{
public:
~CGarbo(){
if (Singleton::m_pInstance)
delete Singleton::m_pInstance;
}
};
static CGarbo Garbo; // 定义一个静态成员,在程序结束时,系统会调用它的析构函数
}
这是非常好的方法,静态成员对象 Garbo 在析构时会自动的消毁单例,我们不用再担心这个问题了。
但是添加一个类的静态对象,总是让人不太满意,所以有人用如下方法来重现实现单例和解决它相应的问题,代码如下:
class Singleton:
{
// 其它成员
public:
static Singleton &GetInstance(){
static Singleton instance;
return instance;
}
private:
Singleton(){};
}
使用局部静态变量,非常强大的方法,完全实现了单例的特性,而且代码量更少,也不用担心单例消毁的问题。
在后期的项目中我全使用了这种方法,可是在项目的开发过程中还是出现了问题,当如下方法使用单例时问题来了,
Singleton singletion = Singleto::GetInstance();
这么做就产生了一个类拷贝的问题,这就为背了单例的特性。
产生这个问题的原因在于,编译器会为类生成一个默认的构造函数,来支持类的拷贝。
最后没有办法,我们要禁止类拷贝和类赋值,禁止程序员用这种方式来使用单例,当时领导的意思是GetInstance()函数返回一个指针而不是返回一个引用,函数代码改为如下:
static Singleton *GetInstance(){
static Singleton instance;
return &instance;
}
可我总是感觉不好,为什么不让编译器不这么干呢。这时我才想起可以显式的声明类拷贝的构造函数,和重载=操作符,新的单例类如下:
class Singleton:
{
// 其它成员
public:
static Singleton &GetInstance(){
static Singleton instance;
return instance;
}
private:
Singleton(){};
Singleton(const Singleton&);
Singleton & operate = (const Singleton&);
}
关于Singleton(const Singleton&);和Singleton & operate = (const
Singleton&);函数,我们要声明成私用的,并且只声明不实现。这样子后如果用上面的方式来使用单例时,不管是在友元类中还是其它的,编
译器都是报错。
不知道这样的单例类是否还会有问题,但在程序中这样子使用已经基本没有问题了。
==3============================================
单例模式的C++实现
Singleton Constructor
ton1 var = 20
ton2 var = 150 当我们要让一个类产生同一个对象对客户端服务的时候,比如管理数据库连接,管理文件IO等,这时我们就要使用到单例模式。下面是该模式的C++实现(注泽说明)
#include
using namespace std;
//单例类的C++实现
class Singleton
{
private:
Singleton();//注意:构造方法私有
virtual ~Singleton();
static Singleton* instance;//惟一实例
int var;//成员变量(用于测试)
public:
static Singleton* GetInstance();//工厂方法(用来获得实例)
int getVar();//获得var的值
void setVar(int);//设置var的值
};
//构造方法实现
Singleton::Singleton()
{
this->var = 20;
cout<<"Singleton Constructor"<
}
Singleton::~Singleton()
{
delete instance;
}
//初始化静态成员
Singleton* Singleton::instance=new Singleton();
Singleton* Singleton::GetInstance()
{
return instance;
}
//seter && getter含数
int Singleton::getVar()
{
return this->var;
}
void Singleton::setVar(int var)
{
this->var = var;
}
//main
int main(int argc, char* argv[])
{
Singleton *ton1 = Singleton::GetInstance();
Singleton *ton2 = Singleton::GetInstance();
cout<<"ton1 var = "<getVar()<
ton1->setVar(150);
cout<<"ton2 var = "<getVar()<
return 0;
}
输出如下:
Singleton Constructor
ton1 var = 20
ton2 var = 150
在输出结果中我们可以看到,构造方法只调用了一次,ton1与ton2是指向同一个对象的。
阅读(755) | 评论(0) | 转发(0) |