摘要:ANSI C++ 中的 Singleton 实现说难不难,说容易也不容易,很多人写 ANSI C++ 的 Singleton class 都有错误。这篇文章讨论怎样在 ANSI c++ 中写 Singleton class, 希望对大家有帮助。

《设计模式》中把 Singleton 写成返回指针:

class Singleton{
public:
static Singleton* Instance();
protected:
Singleton();
private:
static Singleton* _instance;
};

相应的实现 cpp 文件是:

Singleton* Singleton::_instance;
Singleton* Singleton::Instance(){
if( _instance == 0){
_instance = new Singleton;
};
return _instance;
}

将构造函数设计成 protected 的目的是防止在 class 外面 new ,有人可能会设计成 private ,如果考虑到有可能会继承这个类的话,还是将构造函数设计成 protected 比较好,还需要加一个 virtual 析构函数。为了防止别人复制 Singleton 对象:

Singleton* pSingleton = Singleton::Instance();
Singleton s1 = *pSingleton;
Singleton s2 = *pSingleton;
需要将拷贝构造(copy constructor)函数变成 private。

但是这里存在的问题是,什么时候删除 Singleton 对象?按照 C++ 的一个基本原则,对象在哪里创建就在哪里销毁,这里还应该放一个 destroy 方法来删除 Singleton 对象。如果忘了删除就比较麻烦。Instance 函数还存在多线程同时访问的加锁问题。如果把 Instance 函数开始和结尾放上加锁和解锁,整个函数性能会下降很多。这不是一个好的设计。
有一个小小的改动,可以避免忘了删除 Singleton 对象带来内存泄露的问题。那就是用 std:auto_ptr 来包含 Singleton 对象,定义一个class static member auto_ptr 对象,在析构的静态 auto_ptr 变量的时候时候自动删除 Singleton 对象。为了不让用户 delete Singleton 对象,需要将析构函数由 public 变成 protected。以下是头文件 SingletonAutoPtr.h :

#include
using namespace std;
class CSingletonAutoPtr
{
private:
static auto_ptr m_auto_ptr;

static CSingletonAutoPtr* m_instance;
protected:
CSingletonAutoPtr();
CSingletonAutoPtr(const CSingletonAutoPtr&);
virtual ~CSingletonAutoPtr();
//allow auto_ptr to delete, using protected ~CSingletonAutoPtr()
friend class auto_ptr;
public:
static CSingletonAutoPtr* GetInstance();
void Test();
};

对应的 SingletonAutoPtr.cpp 如下:

#include "SingletonAutoPtr.h"

#include

//initial static member vars here

CSingletonAutoPtr* CSingletonAutoPtr::m_instance = NULL;

auto_ptr CSingletonAutoPtr::m_auto_ptr;

/

// Construction/Destruction

/

CSingletonAutoPtr::CSingletonAutoPtr()

{

cout << "CSingletonAutoPtr::CSingletonAutoPtr()" << endl;

//put single object into auto_ptr object

m_auto_ptr = auto_ptr(this);

}

CSingletonAutoPtr::~CSingletonAutoPtr()

{

cout << "CSingletonAutoPtr::~CSingletonAutoPtr()" << endl;

}

CSingletonAutoPtr* CSingletonAutoPtr::GetInstance()

{

//begin lock

//....

if(m_instance == NULL)

m_instance = new CSingletonAutoPtr();

//end lock

//...

return m_instance;

}

void CSingletonAutoPtr::Test()

{

cout << "CSingletonAutoPtr::Test()" << endl;

}

调用方法:

CSingletonAutoPtr* pSingleton = CSingletonAutoPtr::GetInstance();

pSingleton->Test();

写一个 C++ 中的 Singleton 需要这么费劲,大大出乎我们的意料。有很多人从未用过 auto_ptr,而且 std:auto_ptr 本身就并不完美,它是基于对象所有权机制的,相比之下,Apache Log4cxx 中有一个 auto_ptr, 是基于对象计数的,更为好用。只是为了用一个好的 auto_ptr 而不得不用 log4cxx , 对于很多项目来说,也不太好。当然了,ANSI C++ 的 STL 中 std:auto_ptr 对于写上面的例子已经足够用了。

另外一个思路是,把 GetInstance 函数设计成 static member 可能更好,因为一般来说,Singleton 对象都不大,static member 虽然必须一直占用内存,问题不大。这里的析构函数必须设成 public 了。以下是头文件 SingleStaticObj.h

class CSingletonStaticObj

{

private:

static CSingletonStaticObj m_instance;

protected:

CSingletonStaticObj();

CSingletonStaticObj(const CSingletonStaticObj&);

public:

virtual ~CSingletonStaticObj(); //must public

static CSingletonStaticObj& GetInstance();

void Test();

};

对应的 SingleStaticObj.cpp 文件为:

#include "SingletonStaticObj.h"

#include

#include

using namespace std;

CSingletonStaticObj CSingletonStaticObj::m_instance;

CSingletonStaticObj::CSingletonStaticObj()

{

cout << "CSingletonStaticObj::CSingletonStaticObj()" << endl;

}

CSingletonStaticObj::~CSingletonStaticObj()

{

cout << "CSingletonStaticObj::~CSingletonStaticObj()" << endl;

}

CSingletonStaticObj& CSingletonStaticObj::GetInstance()

{

return m_instance;

}

void CSingletonStaticObj::Test()

{

cout << "CSingletonStaticObj::Test()" << endl;

}

调用方法:

CSingletonStaticObj& singleton = CSingletonAutoPtr::GetInstance();

singleton.Test();

从代码量来说,似乎使用 static member ref 更为简单。我更偏向于用这种方法。

但是,并不是所有情况下面都适合用 static member singleton。比如说,GetInstance 需要动态决定返回不同的 instance 的时候,就不能用。举例来说,FileSystem::GetInstance, 在 windows 下面运行可能需要返回 new WinFileSystem, Linux/Unix 下面运行可能需要返回 new LinuxFileSystem,这个时候还是需要用上面的 auto_ptr 包含 singleton 指针的方法。

转载于:https://www.cnblogs.com/alexusli/archive/2008/11/16/1334583.html

C++ 中的Singleton 类的实现相关推荐

  1. 在Java中对Singleton类进行双重检查锁定

    Singleton类在Java开发人员中非常常见,但是它给初级开发人员带来了许多挑战. 他们面临的主要挑战之一是如何使Singleton保持为Singleton? 也就是说,无论出于何种原因,如何防止 ...

  2. singleton 类_在Java中对Singleton类进行双重检查锁定

    singleton 类 Singleton类在Java开发人员中非常常见,但是它给初级开发人员带来了许多挑战. 他们面临的主要挑战之一是如何使Singleton保持为Singleton? 也就是说,无 ...

  3. Java Singleton类中的线程安全性的示例代码

    Java Singleton类中的线程安全性的示例代码 Singleton是最广泛使用的创建设计模式之一,用于限制应用程序创建对象.在实际应用程序中,数据库连接或企业信息系统(EIS)等资源是有限的, ...

  4. Java Singleton类中的线程安全

    Singleton is one of the most widely used creational design pattern to restrict the object created by ...

  5. python中的新式类与旧式类的一些基于descriptor的概念(上)

    python中基于descriptor的一些概念(上) 1. 前言 2. 新式类与经典类 2.1 内置的object对象 2.2 类的方法 2.2.1 静态方法 2.2.2 类方法 2.3 新式类(n ...

  6. Python中的元类是什么?

    元类是什么,我们将它们用于什么? #1楼 请注意,此答案适用于2008年编写的Python 2.x,元类在3.x中略有不同. 元类是使"类"工作的秘诀. 新样式对象的默认元类称为& ...

  7. 深刻理解Python中的元类(metaclass)以及元类实现单例模式

    在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例模式的那一节有些疑惑.因此花了几天时间研究下元类这个概念.通过学习元类,我对pyt ...

  8. JavaScript面向对象编程之Singleton类

    在C#.Java等纯面向对象的语言中,合理使用设计模式将会使我们的模块设计和代码编写更加健壮和清晰.目前JavaScript的编写已经从自身的object-based,被逐渐模拟来很象(至少七八分吧) ...

  9. 得到singleton类?

    在Ruby中,无论类或者对象,都有一个singlton类(或者称为metaclass),有兴趣的话读读过去写的这篇<Ruby的对象模型>.当我们获取某个类或者对象的class属性时,其实会 ...

最新文章

  1. 切换阿里云maven源解决maven中央仓库下载太慢卡顿的问题
  2. 结构型模式:代理模式
  3. html 怎么设置cooki,怎么设置浏览器接受cookie
  4. 使用jQuery时报错:$未被定义
  5. BZOJ3309 DZY Loves Math(莫比乌斯反演+线性筛)
  6. OSChina 周五乱弹 —— 姑娘馋的口水都留下来了。
  7. DateTable复制表行
  8. WinForm设置窗体默认控件焦点
  9. 两年前,梦开始的地方.
  10. java设计模式(创建型)之生成器模式
  11. 74xx系列芯片类型及功能概览
  12. 手机游戏之Jad文件及MANIFEST.MF文件
  13. 【JavaWEB】Redis基础
  14. 广告学计算机平面设计(1)形考5,精编国家开放大学电大专科《计算机平面设计》网络课形考任务1答案.docx...
  15. python特殊字符替换
  16. NoticeBar 通知栏组件,封装好的可直接使用
  17. GitHub 狂飙 30K+star 面试现场, 专为程序员面试打造, 现已开源可下载
  18. python毕业设计作品基于django框架的鲜花水果商城毕设成品(3)后台管理功能
  19. Linux进程内存分析pmap命令
  20. 中科院涉及集成电路(芯片)的院所

热门文章

  1. 和nginx比较_谈谈Nginx和LVS各自的优缺点以及使用
  2. rj45管脚定义_rj45接口定义,rj45插座引脚定义
  3. 程序员怒斥:阿里如此嚣张?为所欲为?谁让你动了我的浏览器
  4. c++读取文件夹下特定文件
  5. 如何用C语言测试,C语言单元测试CMock使用(一) 基本用法
  6. oracle sql的正则表达式,Oracle SQL 语句中正则表达式的应用
  7. 如何创建android布局,如何创建像Android CallLog布局的布局
  8. Eclipse 解决PHP函数代码不能自动提示问题
  9. oracle中ak约束,Oracle自定义聚集函数
  10. STM32低功耗模式测试