C++实现单例模式(包括采⽤C++11中的智能指针)
对于设计模式来说,以前只是看过基础的理论,很多都没有实现和使⽤过。这段时间看到了别⼈C++代码中使⽤了单例模式,发现了很多新的东西,特此总结记录⼀下。说话⽐较啰嗦,希望由浅⼊深,帮助⼤家理解!
单例模式,顾名思义,即⼀个类只有⼀个实例对象。C++⼀般的⽅法是将构造函数、拷贝构造函数以及赋值操作符函数声明为private级别,从⽽阻⽌⽤户实例化⼀个类。那么,如何才能获得该类的对象呢?这时,需要类提供⼀个public&static的⽅法,通过该⽅法获得这个类唯⼀的⼀个实例化对象。这就是单例模式基本的⼀个思想。
下⾯⾸先讨论不考虑线程安全的问题(即:单线程环境),这样能体现出单例模式的本质思想。常见的单例模式分为两种:
1、饿汉式:即类产⽣的时候就创建好实例对象,这是⼀种空间换时间的⽅式
2、懒汉式:即在需要的时候,才创建对象,这是⼀种时间换空间的⽅式
⾸先说⼀下饿汉式:饿汉式的对象在类产⽣的时候就创建了,⼀直到程序结束才释放。即对象的⽣存周期和程序⼀样长,因此 该实例对象需要存储在内存的全局数据区,故使⽤static修饰。代码如下(注:类
的定义都放在了⼀个头⽂件CSingleton.h中,为了节省空间,该类有些实现和定义就放在测试的主⽂件中,没有单独创建⼀个CSingleton.cpp⽂件):
头⽂件:
// 饿汉式单例的实现
#ifndef C_SINGLETON_H
#define C_SINGLETON_H
#include<iostream>
using namespace std;
class CSingleton
{
private:
CSingleton(){ cout << "单例对象创建!" << endl; };
CSingleton(const CSingleton &);
CSingleton& operator=(const CSingleton &);
~CSingleton(){ cout << "单例对象销毁!" << endl; };
static CSingleton myInstance; // 单例对象在这⾥!
public:
static CSingleton* getInstance()
{
return &myInstance;
}
};
#endif
源⽂件:
//主⽂件,⽤于测试⽤例的⽣成
#include<iostream>
#include"CSingleton.h"
using namespace std;
CSingleton CSingleton::myInstance;
int main()
{
CSingleton *ct1 = CSingleton::getInstance();
CSingleton *ct2 = CSingleton::getInstance();
CSingleton *ct3 = CSingleton::getInstance();
return 0;
}
对于饿汉式来说,是 线程安全的。运⾏结果如下所⽰:
能够看出,类的实例只有⼀个,并且正常销毁。这⾥,问题来了如果在类⾥⾯的定义改成如下形式:
// 饿汉式单例的实现
#ifndef C_SINGLETON_H
#define C_SINGLETON_H
#include<iostream>
using namespace std;
class CSingleton
{
private:
CSingleton(){ cout << "单例对象创建!" << endl; };
CSingleton(const CSingleton &);
CSingleton& operator=(const CSingleton &);
~CSingleton(){ cout << "单例对象销毁!" << endl; };
static CSingleton *myInstance; // 这⾥改了!
public:
static CSingleton* getInstance()
{
return myInstance; // 这⾥也改了!
}
};
#endif
同样源⽂件改成如下:
//主⽂件,⽤于测试⽤例的⽣成
#include<iostream>
#include"CSingleton.h"
using namespace std;
CSingleton * CSingleton::myInstance=new CSingleton();
单例模式的几种实现方式
int main()
{
CSingleton *ct1 = CSingleton::getInstance();
CSingleton *ct2 = CSingleton::getInstance();
CSingleton *ct3 = CSingleton::getInstance();
return 0;
}
结果如下:
咦!怎么没有进⼊析构函数?这⾥就有问题了,如果单例模式的类中申请了其他资源,就⽆法释放,导致内存泄漏!
原因:此时全局数据区中,存储的并不是⼀个实例对象,⽽是⼀个实例对象的指针,即⼀个地址变量⽽已!实例对象呢?在堆区,因为是通过new得来的!虽然这样能够减⼩全局数据区的占⽤,把实例对象这⼀⼤坨都放到堆区。可是!如何释放资源呢?
⾸先能想到的第⼀个⽅法:我⾃⼰⼿动释放呀!我在程序结束的时候delete不就可以了?对!这是可以的,程序如下:
// 饿汉式单例的实现
#ifndef C_SINGLETON_H
#define C_SINGLETON_H
#include<iostream>
using namespace std;
class CSingleton
{
private:
CSingleton(){ cout << "单例对象创建!" << endl; };
CSingleton(const CSingleton &);
CSingleton& operator=(const CSingleton &);
~CSingleton(){ cout << "单例对象销毁!" << endl; };
static CSingleton *myInstance;
public:
static CSingleton* getInstance()
{
return myInstance;
}
static void releaseInstance() // 这⾥加了个⽅法
{
delete myInstance;
}
};
#endif
源⽂件:
//主⽂件,⽤于测试⽤例的⽣成
#include<iostream>
#include"CSingleton.h"
using namespace std;
CSingleton * CSingleton::myInstance=new CSingleton();
int main()
{
CSingleton *ct1 = CSingleton::getInstance();
CSingleton *ct2 = CSingleton::getInstance();
CSingleton *ct3 = CSingleton::getInstance();
CSingleton::releaseInstance(); // ⼿动释放
return 0;
}
运⾏结果如下
运⾏结果没问题!可是,要是我写着写着我忘记了,没有显式调⽤释放的函数怎么办?如果有⼀个⾃动释放的⽅法就好了! 天⽆绝⼈之路,⽅法⼆如下:
// 饿汉式单例的实现
#ifndef C_SINGLETON_H
#define C_SINGLETON_H
#include<iostream>
using namespace std;
class CSingleton
{
private:
CSingleton(){ cout << "单例对象创建!" << endl; };
CSingleton(const CSingleton &);
CSingleton& operator=(const CSingleton &);
~CSingleton(){ cout << "单例对象销毁!" << endl; };
static CSingleton *myInstance;
public:
static CSingleton* getInstance()
{
return myInstance;
}
private:
// 定义⼀个内部类
class CGarbo{
public:
CGarbo(){};
~CGarbo()
{
if (nullptr != myInstance)
{
delete myInstance;
myInstance = nullptr;
}
}
};
// 定义⼀个内部类的静态对象
// 当该对象销毁时,顺带就释放myInstance指向的堆区资源
static CGarbo m_garbo;
};
#endif
源⽂件如下:
//主⽂件,⽤于测试⽤例的⽣成
#include<iostream>
#include"CSingleton.h"
using namespace std;
CSingleton * CSingleton::myInstance=new CSingleton();
CSingleton::CGarbo CSingleton::m_garbo; // 注意这⾥
int main()
{
CSingleton *ct1 = CSingleton::getInstance();
CSingleton *ct2 = CSingleton::getInstance();
CSingleton *ct3 = CSingleton::getInstance();
return 0;
}
运⾏结果如下:
可见能够正常释放堆区申请的资源了!问题解决!这⾥⼜会想到,C++11中把boost库中的智能指针变成标准库的东西。智能指针可以在引⽤计数为0的时候⾃动释放内存,⽅便使⽤者管理内存,为什么不尝试⽤⼀下智能指针呢?现在修改代码如下(不可以正常运⾏):
// 饿汉式单例的实现
#ifndef C_SINGLETON_H
#define C_SINGLETON_H
#include<iostream>
#include<memory>
using namespace std;
class CSingleton
{
private:
CSingleton(){ cout << "单例对象创建!" << endl; };
CSingleton(const CSingleton &);
CSingleton& operator=(const CSingleton &);
~
CSingleton(){ cout << "单例对象销毁!" << endl; };
static shared_ptr<CSingleton> myInstance;
public:
static shared_ptr<CSingleton> getInstance()
{
return myInstance;
}
};
#endif
主⽂件

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。