c++单例模式与线程安全(一)
1.什么是单例模式单例模式是设计模式中的一种,也是最常用和简单的设计模式之一。单例模式,顾名思义,它是为了保证一个类只能有一个实例或者说该类只能被实例化一次。标准的定义如下:单例模式确保一个类只有一个实例,并且自行实例化向整个系统。单例类提供了全局的访问点。2.单例模式的实现假设我们有一个配置文件类,提供了read配置文件,set配置文件等方法,但是系统中只需要一个配置文件,该类只需要实例...
1.什么是单例模式
单例模式是设计模式中的一种,也是最常用和简单的设计模式之一。单例模式,顾名思义,它是为了保证一个类只能有一个实例或者说该类只能被实例化一次。标准的定义如下:
单例模式确保一个类只有一个实例,并且自行实例化向整个系统。单例类提供了全局的访问点。
2.单例模式的实现
假设我们有一个配置文件类,提供了read配置文件,set配置文件等方法,但是系统中只需要一个配置文件,该类只需要实例化一次,下面我们看看如何将配置文件类慢慢的转化成一个单例类。
class Config
{
public:
Config(){cout << "config()" << endl;}
~Config(){cout << "~Config()" << endl;}
void ReadConfig(){cout << "ReadConfig()" << endl;}
void SetConfig(){cout << "WriteConfig()" << endl;}
};
1.我们都知道,一般的类都可以通过new来生成一个新的对象,而单例模式是不允许有多个实例的,也就是不允许在类的外部通过new来创建对象,因此为了禁止类的外部通过new来创建实例,我们需要把config类的构造函数声明为私有的(private),这样在类的外部就不可以创建实例了。修改如下:
private:
Config(){cout << "config()" << endl;}
2.经过上面的改造,config类不允许在外部创建对象,那么我们还可以在类的内部创建唯一的实例并且将该实例保存,为了保存该实例,我们需要新建一个静态的私有成员变量。
private: static Config* temp;
这里只管定义,不能初始化,在c++中静态成员的初始化需要在类外进行。
3.由于类内部创建的实例用了一个私有的成员变量保存,为了让外部能够访问实例,我们还需要增加一个公有的成员来访问私有变量。
public:
static Config* getInstance()
{
if(temp == NULL)
temp = new Config();
return temp;
}
在getInstance函数中,会先判断temp是否为空,如果是空的,就先实例化一个对象存放在temp中,再返回。其次,函数被声明为static,因此调用该函数时可以直接用类名来访问,不需要创建对象。
现在看一下完整的代码:
#include <iostream>
using namespace std;
class Config
{
private:
Config(){cout << "config()" << endl;}
private: static Config* temp;
public:
~Config(){cout << "~Config()" << endl;}
void ReadConfig(){cout << "ReadConfig()" << endl;}
void WriteConfig(){cout << "WriteConfig()" << endl;}
public:
static Config* getInstance()
{
if(temp == NULL)
temp = new Config();
return temp;
}
};
Config* Config::temp = NULL;
int main()
{
Config* a = Config::getInstance();
Config* b = Config::getInstance();
return 0;
}
运行结果如下:
从运行结果中可以看到config类只调用了一次构造函数,即只实例化了一次。
3.饿汉单例模式和懒汉单例模式
单例模式的实现大致可以分为两种,饿汉和懒汉。
饿汉单例:在类加载时就创建实例
懒汉单例:在第一次使用时才创建实例。
知道以上两个概念之后,再看看上面config类的单例模式是哪一种呢?
很显然,由语句:Config* Config::temp = NULL;可以看出,一开始没有创建实例的,只有在Config* a = Config::getInstance();才开始第一次创建实例,这里也是第一次使用的地方,因此上面的单例模式属于在第一次使用时才创建实例,属于懒汉单例模式。
还是以config类为例,看一看饿汉单例模式是如何实现的。
#include <iostream>
using namespace std;
class Config
{
private:
Config(){cout << "config()" << endl;}
private: static Config* temp;
public:
~Config(){cout << "~Config()" << endl;}
void ReadConfig(){cout << "ReadConfig()" << endl;}
void WriteConfig(){cout << "WriteConfig()" << endl;}
public:
static Config* getInstance()
{
return temp;
}
};
Config* Config::temp = new Config();//创建实例
int main()
{
cout << "main running" << endl;
Config* a = Config::getInstance();
Config* b = Config::getInstance();
return 0;
}
运行代码结果如下:
可以看到,在进入main函数之前,config的实例就已经被创建了。
好了,关于懒汉和饿汉的单例模式基础实现就先介绍到这里,下一篇文章,我们将会分析一下两种单例模式的线程安全问题。
更多推荐
所有评论(0)