单例模式简介以及C++版本的实现
作者:网络转载 发布时间:[ 2015/9/18 13:43:45 ] 推荐标签:测试开发技术 .NET
本篇博文主要内容参考 C++的单例模式一文,在此,为原作者耐心细致的分析讲解,表示感谢。本文将结合此篇文章,给出自己做实验后的理解以及代码,作为学习的小结。
单例模式,它的意图是保证一个类仅拥有一个实例,并在对外提供一个全局访问点,该实例被所有模块共享。这种模式的应用范围很广,比如系统日志输出,操作系统的窗口管理器,PC连接的键盘等等。
单例模式是一种设计模式,它的具体实现和各种语言特性有关,这里主要介绍在C++上面的实现,测试平台为Win7 64位,VS2010开发环境。
根据参考博文中的例子,在此先列举一下各种实现策略,以下均以CSingleton为类名来举例。
1. 使用一个全局对象,比如叫CSingleton g_instance,优点是访问方便,缺点是不能保证此类对象,除了全局对象外,还能够创建CSingleton的局部实例。
2. 使用类的静态成员变量,此变量为私有的静态成员指针,如static CSingleton1 *m_pInstance;此时,需要考虑让类自己在合适的时候释放掉此成员指针所指向的内容。
3. 使用类的静态成员变量,此变量为私有的静态成员,如static CSingleton1 m_pInstance;
在给出代码前,要说明几个知识点:
1. 类的静态成员(包括 成员变量和成员函数),属于类自身,所有实例对象均共享同一副本。
2. 静态成员初始化操作在进入main函数之前,已经分配空间并且完成初始化。静态成员变量必须在类体外初始化,通过类似 CSingleton1* CSingleton::m_pInstance = NULL的方式来定义初始化数值。如果不初始化,那么此成员不会被分配空间,也不会在类中存在。
4. 静态成员在程序退出main函数后,会转到CRT类函数的清理中,完成程序静态变量、类的析构函数等资源释放的调用,具体细节无需考虑,只需要知道退出main函数还需要做清理工作行。
3. 声明在类内部的类,成为嵌套类,它一般用来声明只在类内部使用的类。如果一定要在外部使用,需要加域解析符::
好了,基本铺垫完成,开始码代码,先从简单开始。
静态类变量方式,起先可以是类的成员变量,但需要在外部进行初始化,不优雅。其实,在类的静态成员函数中声明静态局部类变量,是一种更简洁的方法。
class CSingleton
{
private:
CSingleton() //构造函数是私有的
{
}
CSingleton(const CSingleton &);
CSingleton & operator = (const CSingleton &);
public:
static CSingleton & GetInstance()
{
static CSingleton instance; //局部静态变量
return instance;
}
};
静态类指针方式:这种方式实现,因为有分配空间,所以需要考虑的东西比较多。参考C++的单例模式一文中的代码,下面给出经过亲身实践后,无内存泄露的代码。重要的地方,都写上了注释,便于大家理解。
// singlethon.cpp : 定义控制台应用程序的入口点。
#include <iostream>
#include <Windows.h>
using namespace std;
//用于开启CRT 内存泄露检测问题
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
//多线程保护锁类
class Lock
{
private:
CRITICAL_SECTION m_cs; // 封装临界区
Lock(){};
Lock(const Lock&){};
Lock& operator=(const Lock&){};
public:
Lock(CRITICAL_SECTION cs):m_cs(cs)
{
InitializeCriticalSection(&m_cs);
}
void StartLock()
{
EnterCriticalSection(&m_cs);
}
void StopLock()
{
// 离开临界区
//LeaveCriticalSection(&m_cs);
}
~Lock()
{
// 离开临界区 放在这里 貌似更好点
LeaveCriticalSection(&m_cs);
// 临界区不用的时候,进行销毁释放占用资源
DeleteCriticalSection(&m_cs);
}
};
//自己仿照参考,实现一个单例模式
class Singlethon
{
//内嵌类,只能在Singlethon中使用,无法直接在外部使用
class CGarbo //的作用,在析构函数中,删除Singlethon的实例
{
public:
CGarbo()
{
cout << "constructor CGarbo"<<endl;
}
~CGarbo()
{
if(Singlethon::m_pInstance)
{
cout << "execute CGarbo destructor function"<<endl;
delete Singlethon::m_pInstance;
}
}
};
private:
Singlethon(){cout << "constructor Singlethon "<<endl;}; //禁止直接声明 Singlethon single;
Singlethon(const Singlethon&){}; //禁止间接声明 Singlethon single2(*(Singlethon::GetInstance()));
// 或者 Singlethon single2 = (*(Singlethon::GetInstance()));
Singlethon& operator=(const Singlethon&){}; //禁止赋值操作 Singlethon single;single = *(Singlethon::GetInstance());
static Singlethon* m_pInstance;
static CGarbo Garbo; //静态成员变量,程序结束时,系统自动调用它的析构函数
static CRITICAL_SECTION cs;
public:
static Singlethon* GetInstance();
~Singlethon()
{
cout << "execute Singlethon destructor function"<<endl;
//不能在这里释放自身,因为CGarbox的析构函数会先于自身析构执行,而它在执行时,会调用 delete Singlethon::m_pInstance;
//这会触发Singlethon自身的析构函数,而这里,再一次调用 delete Singlethon::m_pInstance,这造成无限循环
//终会报错堆栈溢出的错误
#if 0
if(Singlethon::m_pInstance)
delete Singlethon::m_pInstance;
Singlethon::m_pInstance = NULL;
#endif
}
};
//以下三句话,缺一不可
Singlethon::CGarbo Singlethon::Garbo;
Singlethon* Singlethon::m_pInstance = NULL;
Singlethon* Singlethon::GetInstance()
{
if (NULL == m_pInstance)
{
Lock lock(cs);
lock.StartLock();
if (NULL == m_pInstance)
{
m_pInstance = new Singlethon;
}
lock.StopLock();
} //正常退出或者异常抛出,这里都会自动调用lock的析构函数,因为lock的作用域是局部的
return m_pInstance;
}
int main()
{
//开启CRT内存泄露检测功能
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
Singlethon* p1 = Singlethon::GetInstance();
Singlethon* p2 = Singlethon::GetInstance();
if ( p1 == p2)
{
cout << "单例模式测试成功!!"<<endl;
}
else
{
cout << "单例模式测试失败!!"<<endl;
}
return 0;
}
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11