一、单例模式
首先我们应该明确,一个单例模式应该满足以下3点:
1. 当前类最多只能创建一个实例。
2. 自己创建这个实例(而不是调用者创建)。
3. 向整个系统提供全局访问点访问这个实例。
首先,我们先写一个普通的类:
#include<iostream>
using namespace std;
class CSingleton {
};
int mian() {
return 0;
}
(一)我们考虑如何做到让一个类,只能自己创建实例
构造私有化
#include<iostream>
using namespace std;
class CSingleton {
private://只能类内调用
CSingleton() {
}
};
int mian() {
return 0;
}
之后我们需要一个类外调用的接口
#include<iostream>
using namespace std;
class CSingleton {
private:
CSingleton() {
}
CSingleton* CreateSingleton()
{
CSingleton* pin = new CSingleton;
return pin;
}
};
int mian() {
return 0;
}
但是我们不能确保这个对象是唯一的,所以我们可以让pin作为一个旗帜,如果不为空才可以被创建。
#include<iostream>
using namespace std;
class CSingleton {
private:
CSingleton* Pin;
CSingleton():Pin(nullptr){
}
CSingleton* CreateSingleton()
{
if(!Pin)
Pin = new CSingleton;
return Pin;
}
};
int mian() {
return 0;
}
但是此时我们想要调用此单例时我们会发现,首先我们将其改为公共类型,其次我们必须创建对象才可以使用,为了解决这个问题,我们可以想到,类中不依赖对象存在的函数——静态函数
所以我们将创造函数修改为静态函数
注意:静态函数只能调用静态成员属性,所以pin也需要进行修改,及其初始化位置
#include<iostream>
using namespace std;
class CSingleton {
private:
static CSingleton* Pin;
CSingleton(){
}
public:
static CSingleton* CreateSingleton()
{
if(!Pin)
Pin = new CSingleton;
return Pin;
}
};
CSingleton* CSingleton:: Pin = nullptr;
int mian() {
return 0;
}
之后我们来测试一下
#include<iostream>
using namespace std;
class CSingleton {
private:
static CSingleton* Pin;
CSingleton(){
}
public:
static CSingleton* CreateSingleton()
{
if(!Pin)
Pin = new CSingleton;
return Pin;
}
};
CSingleton* CSingleton:: Pin = nullptr;
int main() {
CSingleton* pSin1 = CSingleton::CreateSingleton();
CSingleton* pSin2 = CSingleton::CreateSingleton();
cout << pSin1 << " " << pSin2 << endl;
return 0;
}
结果为
但是我们会发现,我们申请的空间并没有被回收,所以我们需要一个回收函数
#include<iostream>
using namespace std;
class CSingleton
{
private:
static CSingleton* pSin;
CSingleton(){
}
public:
static CSingleton* CreateSingleton() {
if(!pSin)
pSin = new CSingleton;
return pSin;
}
static void DestorySingleton()
{
if (pSin)
{
delete pSin;
pSin = nullptr;
}
}
};
CSingleton* CSingleton::pSin = nullptr;
int main() {
CSingleton* pSin1 = CSingleton::CreateSingleton();
CSingleton* pSin2 = CSingleton::CreateSingleton();
cout << pSin1 << " " << pSin2 << endl;
return 0;
}
同时,我们考虑是否能够将主函数中指向单例的指针一同销毁,我们可以写一个带参数的销毁函数,且由于我们需要修改内容,所以传参方式我们选择引用传参
#include<iostream>
using namespace std;
class CSingleton
{
private:
static CSingleton* pSin;
CSingleton(){
}
public:
static CSingleton* CreateSingleton() {
if(!pSin)
pSin = new CSingleton;
return pSin;
}
static void DestorySingleton(CSingleton*& psin)
{
if (pSin)
{
delete pSin;
pSin = nullptr;
}
psin = nullptr;
}
};
CSingleton* CSingleton::pSin = nullptr;
int main() {
CSingleton* pSin1 = CSingleton::CreateSingleton();
CSingleton* pSin2 = CSingleton::CreateSingleton();
cout << pSin1 << " " << pSin2 << endl;
CSingleton::DestorySingleton(pSin1);
CSingleton::DestorySingleton(pSin2);
return 0;
}
但是此写法依旧存在问题,例如当下列情况出现时
CSingleton* pSin1 = CSingleton::CreateSingleton();
CSingleton pSin(*pSin1);
cout << pSin1 << " " <<&pSin<< endl;
结果仍出现两个不同的实例
为了解决这种情况,我们可以将拷贝构造函数进行弃用
class CSingleton
{
private:
static CSingleton* pSin;
CSingleton(){
}
CSingleton(const CSingleton&) = delete;//禁用拷贝构造
~CSingleton()
{
}
public:
static CSingleton* CreateSingleton() {
if(!pSin)
pSin = new CSingleton;
return pSin;
}
static void DestorySingleton(CSingleton*& psin)
{
if (pSin)
{
delete pSin;
pSin = nullptr;
}
psin = nullptr;
}
};
到此,一个单例模式差不多完成了,但是其实还存在一个隐形的问题:此单例模式在单线程下可以实现,但多线程需要加锁,之后会进行补充
1.1懒汉式
当调用单例的接口时才会创建
上述方法就是一种懒汉式
下面展示懒汉式的另一种实现
刚刚我们提到上面单例多线程下会创建多个,我们可以这样写
#include<iostream>
using namespace std;
class CSingleton
{
private:
static CSingleton* pSin;
CSingleton() {
}
CSingleton(const CSingleton&) = delete;
~CSingleton()
{
}
public:
static CSingleton* CreateSingleton()
{
static CSingleton sin;
return &sin;
}
};
int main()
{
CSingleton *pSin1 = CSingleton::CreateSingleton();
cout << pSin1 << endl;
CSingleton* pSin2 = CSingleton::CreateSingleton();
cout << pSin2 << endl;
return 0;
}
运行结果为
这种实现方法与第一种相比,虽然避免了多线程下创建多个的问题,但是却无法将单例手动销毁
时间换空间的,直到第一次调用,才会执行构造,开辟空间。
1.2饿汉式
饿汉式和懒汉式相反,
饿汉式是一开始就将对象创建出来,相当于空间换时间的做法。
那我们就会考虑那种方式可以产生这种效果——静态类成员属性
#include<iostream>
using namespace std;
class CSingleton
{
private:
static CSingleton sin;
static CSingleton* pSin;
CSingleton() {
}
CSingleton(const CSingleton&) = delete;
~CSingleton()
{
}
public:
static CSingleton* CreateSingleton()
{
return &sin;
}
};
CSingleton CSingleton::sin;
int main()
{
CSingleton *pSin1 = CSingleton::CreateSingleton();
cout << pSin1 << endl;
CSingleton* pSin2 = CSingleton::CreateSingleton();
cout << pSin2 << endl;
return 0;
}
在懒汉式的基础上,稍加改进......