单例模式初探

大致思路是,将该类的构造函数定义为私有方法,代码其他地方不能实例化该对象,只能通过调用该类的一个静态成员函数(get_instance())来获取这个唯一实例。

更进一步,把该类的复制构造函数和重载的=赋值运算也声明为私有,即Singleton(const Singleton)和 Singleton & operate = (const Singleton&)函数,需要声明成私有的,并且只声明不实现.

这里有个小坑是,当这个唯一的实例没有被创建时,有多个线程同时调用get_instance(),可能会造成过个实例的创建。因此需要牺牲一点效率做处理,如:加锁和双检测(double-check)以保护。

对于实例的创建,又有饿汉和懒汉两种模式,懒汉即在使用对象时才进行创建,如上面提到的,存在线程安全性问题。有一点补充的是,C++0X以后,要求编译器保证内部静态变量的线程安全性,可以不加锁。但C++ 0X以前,仍需要加锁。

而饿汉模式是,在进入主函数之前就由主线程以单线程方式完成了初始化,不必担心多线程问题,在性能需求较高时,应使用这种模式,避免频繁的锁争夺。但是多个单例模式的类相互引用时,由于静态成员变量 初始化顺序没有保障,会有坑出现,详见:

http://blog.csdn.net/crayondeng/article/details/24853471

以一个日志类为例:

考虑到日志文件只有一个的特点,我们用一个单例模式来实现,在其构造函数中完成对日志文件的初始化(打开和基本设置),其后每次读写操作只需拿到有效的文件句柄。

类的声明如下:

class Logger{

	public:
		static Logger* get_instance();
		int log_write(String &str, int errcode);
		int log_read(String &str, int errcode);
		static int mutex_init();

		static pthread_mutex_t *mutex_for_creating;
	private:
		Logger();
		~Logger();

		Logger(const Logger &);
		Logger & operator = (const Logger &);

		static Logger* p_logger;
		int fd;
};

懒汉模式获取实例的函数大致如下:

static Logger* Logger::get_instance()
{
	if (p_logger)
		return p_logger;

	pthread_mutex_lock(&mutex_for_creating);
	if (!p_logger) {
		p_logger = new Logger;
	}
	pthread_mutex_unlock(&mutex_for_creating);
	return p_logger;
}

两个if语句即上面提到的双检测机制,确保线程安全。

进入程序前有两个初始化:

static Logger::p_logger = NULL;

static int Logger::mutex_init()
{
	if ((mutex_for_creating = new pthread_mutex_t) == NULL)
		return -1;

	pthread_mutex_init(&mutex_for_creating, NULL);
	return 0;
}

而对于饿汉模式:

将实例的指针p_logger置为public,直接在进入主程序前new一个对象:

static Logger::p_logger = new Logger;

关于对象生命周期,一般可以不考虑,因为该对象通常是存在在整个程序的生命周期,随着程序的退出自动销毁。

而有些情况,如:“在类中,有一些文件锁了,文件句柄,数据库连接等等,这些随着程序的关闭而不会立即关闭的资源,必须要在程序关闭前,进行手动释放”[1]

也有一些参考的方法,如添加CGarbo类专门对单例对象进行回收,或者是用静态局部变量,如:http://blog.yangyubo.com/2009/06/04/best-cpp-singleton-pattern/和http://blog.csdn.net/Hackbuteer1/article/details/7460019

以及http://www.programlife.net/cpp-singleton-memory-retrieve.html

静态局部变量具有局部作用域,它只被初始化一次,自从第一次被初始化直到程序运行结束都一直存在,它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见。

简单地说static 局部变量相对于局部变量:改变局部变量的存储位置,不改变局部变量的作用范围。

参考:[1] http://www.jellythink.com/archives/82

时间: 2024-12-14 20:34:07

单例模式初探的相关文章

Android开发之单例模式初探(源代码分享)

单例模式是什么呢?是Java23中模式之一,在Android开发中也有着广泛的运用,比如Calander类,在创建对象的时候并不是通过 new Calander而是Calander.getInstnce(),这就是单例模式的一种运用,应用的场合是什么呢?我们在很多时候有些对象只需要一个就够了,并不需要多个,就比如古代的皇帝,一山不容二虎,老虎多了只有坏处没有好处.它的作用就是保证整个应用程序中某个实例有且只有一个,one  is all! 单例模式呢分为两种一个是饿汉模式一个是懒汉模式,让我们先

iOS之单例模式初探

单例模式可能是设计模式中最简单的形式了,这一模式的意图就是使得类中的一个对象成为系统中的唯一实例.它提供了对类的对象所提供的资源的全局访问点.因此需要用一种只允许生成对象类的唯一实例的机制.下面让我们来看下单例的作用: 可以保证的程序运行过程,一个类只有一个示例,而且该实例易于供外界访问 从而方便地控制了实例个数,并节约系统资源. 单例模式的使用场合 类只能有一个实例,并且必须从一个为人数值的访问点对其访问. 这个唯一的实例只能通过子类化进行拓展,并且拓展的对象不会破坏客户端代码. 在Objec

第62课 单例类模板

1. 单例需求的提出 (1)在架构设计时,某些类在整个系统生命期中最多只能有一个对象存在(Single Instance) (2)问题:如何定义一个类,使得这个类最多只能创建一个对象 2. 单例模式 (1)要控制类的对象数目,必须对外隐藏构造函数 (2)思路 ①将构造函数的访问属性设置为private ②定义instance,并初始化为NULL ③提供静态函数getInstance来返回单例实例,并判断当instance的值为空时,并创建对象,并保存在instance指针中,非空值时直接返回in

初探单例模式学习笔记

一.如何防止一个类产生多个实例呢? 1.不做任何措施,贴出一幅海报,通知所有程序员不能对这个类创建多个实例  (不现实) 2.让这个类无法创建另一个实例    -> 单例模式 二.但是对类进行实例化,它的决定权在类的外部,如何将决定权回归类的自身呢? -> 将构造函数变成private类型  ,不允许外界直接调用构造方法创建实例 三.但我们总要给外界提供一个途径获得类的实例 class T { private T(); public static T getInstance() { retur

Spring.Net 初探

Spring.Net 初探之牛刀小试 又是一个周末,感受着外面30°的高温,果断宅在家里,闲来无事,就研究了一下spring .net 框架, 在这里不得不说 vs2013确实是一个强大的开发工具(起码对于.net开发来说是这样的),哈哈 废话不多说了开始展示一下我的成果吧. 1.  项目采用多层架构 IRepository/Repository/Service/Web层,而spring.net主要安装在service层,这样做的目的就是使注入和web层分开,使代码逻辑更加清晰,而在web层只需

WCF初探-27:WCF中的实例化

理解WCF中的实例化机制 “实例化”是指对用户定义的服务对象以及与其相关的 InstanceContext 对象的生存期的控制.也就是说我们的客户端程序在调用服务端方法时,需要实例化一个服务端代理类对象,实例化就是对这个对象的生命周期的管理(比如:代理服务对象的创建,对象调用服务端方法后需要对其进行的回收处理). 实例化行为(使用 System.ServiceModel.ServiceBehaviorAttribute.InstanceContextMode 属性进行设置)控制如何创建 Inst

Java设计模式学习笔记,一:单例模式

开始学习Java的设计模式,因为做了很多年C语言,所以语言基础的学习很快,但是面向过程向面向对象的编程思想的转变还是需要耗费很多的代码量的.所有希望通过设计模式的学习,能更深入的学习. 把学习过程中的笔记,记录下来,只记干货. 第一部分:单例模式的内容 单例模式:类只能有一个实例. 类的特点:1.私有构造器:2.内部构造实例对象:3.对外提供获取唯一实例的public方法. 常见的单例模式实现有五种形式: 1.饿汉式. 2.懒汉式. 3.双重检查锁式. 4.静态内部类式. 5.枚举式. 以下分别

进阶之初探nodeJS

一.前言 在"初探nodeJS"随笔中,我们对于node有了一个大致地了解,并在最后也通过一个示例,了解了如何快速地开启一个简单的服务器. 今儿,再次看了该篇随笔,发现该随笔理论知识稍多,适合初级入门node,固萌生一个想法--想在该篇随笔中,通过一步步编写一个稍大一点的node示例,让我们在整体上更加全面地了解node. so,该篇随笔是建立在"初探nodeJS"之上的,固取名为"进阶之初探nodeJS". 好了,侃了这多,那么我们即将实现一个

【python之路33】开发模式单例模式

1.单例模式指的是创建单个实例,例如:数据库连接池中包含10个数据库连接,用户访问数据时随机从连接池中拿出一个进行连接,其他用户再次访问时不再创建对象进行连接 #!usr/bin/env python # -*- coding:utf-8 -*- class ConnecttionPool: __instance = None def __init__(self): self.ip = '222.133.177.67' self.port = '3306' self.username = 'od