单例模式的概念与简单实现
单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
单例模式的一般代码如下:
class CSingleton
{
private:
CSingleton() //构造函数是私有的
{
}
static CSingleton *m_pInstance;
public:
static CSingleton * GetInstance()
{
if(m_pInstance == NULL) //判断是否第一次调用
m_pInstance = new CSingleton();
return m_pInstance;
}
};
有意思的是,我们不知道什么时候去释放这个指针所指向的空间,这个实例的析构函数是如何调用呢?解决办法如下:
class CSingleton
{
private:
CSingleton()
{
}
static CSingleton *m_pInstance;
class CGarbo //它的唯一工作就是在析构函数中删除CSingleton的实例
{
public:
~CGarbo()
{
if(CSingleton::m_pInstance)
delete CSingleton::m_pInstance;
}
};
static CGarbo Garbo; //定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数
public:
static CSingleton * GetInstance()
{
if(m_pInstance == NULL) //判断是否第一次调用
m_pInstance = new CSingleton();
return m_pInstance;
}
};
按照如上方法,在程序退出的时候系统将自动析构所有的全局变量,这个成静态成员变量也会被析构,从而调用单例类的析构函数。
换一种想法,我们可以在单例类中返回一个静态变量,这样不就很容易的吗?
#include<iostream>
#include <stdio.h>
using namespace std;
class string1
{
private:
char *ptr;
public:
string1(char *s)
{
ptr=new char[strlen(s)+1];
strcpy(ptr,s);
}
~string1()
{
delete ptr;
cout<<"调用了析构函数"<<endl;
}
void print()
{
cout<<ptr<<endl;
}
string1(const string1 &p)
{ //拷贝构造函数
ptr=new char[strlen(p.ptr)+1];
strcpy(ptr,p.ptr);
cout<<"调用了拷贝构造函数"<<endl;
}
string1 operator=(const string1 & s)
{
if(this==&s) return *this;
delete ptr;
ptr=new char[strlen(s.ptr)+1];
strcpy(ptr,s.ptr);
return *this; // 如果返回的不是引用就会调用拷贝构造函数 如果没有自己定义拷贝构造函数就会出问题 加上的话也可以实现连续赋值的情况,不过调用的拷贝构造函数就很多
///中间的内存消耗很多
}
};
class CSingleton
{
private:
CSingleton(int o) //构造函数是私有的
{
p=o;
}
CSingleton(const CSingleton &);
CSingleton & operator = (const CSingleton &);
int p;
public:
/* CSingleton(const CSingleton & s)
{
this->p=s.p;
}*/
static CSingleton & GetInstance(int x)
{
static CSingleton instance(x); //局部静态变量
return instance;
}
int print()
{
return p;
}
};
void main()
{
CSingleton &s=CSingleton::GetInstance(5);
CSingleton &o=CSingleton::GetInstance(6);
cout<<&s<<&o<<endl;
cout<<s.print()<<endl;
cout<<o.print()<<endl;
getchar();
}
在这里,我们将构造函数私有化,并且把赋值运算符和拷贝构造函数都私有化了。这样我们只能通过引用来取得实例。也可以实现单例功能。
以上的讨论都集中于单线程,多线程的问题还需要再深入研究一下同步和加锁。