C++中的单例模式——2

有时候实现了一个类,但只需要创建出一个实例化的对象就能完成需求,如果有太多的对象不仅浪费内存空间也会使得代码数据不那么好维护,因此会需要设计出一个只能生成一个实例的类;

首先,要使得这个类只能实例化出一个对象,那么它的构造函数肯定不能够被外部随意调用,因此应该将类的构造函数的访问限定符设定为私有的,但是这样的话,如何获得唯一一个的实例化对象呢?可以设计一个成员函数,这个成员函数只能分配出唯一一个该类对象的内存空间,并且返回指向这块空间的指针给申请的对象,因此,可以将类设计为如下:

#include <iostream>
using namespace std;

class Singleton
{
private:
    Singleton()
    {}  
    Singleton(Singleton& s); 
    Singleton& operator=(Singleton& s); 

public:
    static Singleton*& GetInstance()
    {   
        if(_instance == NULL)
        { 
            _instance = new Singleton();
        } 
        return _instance;
    }
    
    ~Singleton()
    {
        if(_instance != NULL)
            delete _instance;
    }

private:
    static Singleton *_instance;
};
Singleton* Singleton::_instance = NULL;

上面的栗子中将构造函数、拷贝构造和赋值运算符的重载函数的访问限定符置为私有的,外界不能通过这些函数实例化出对象;然后设计了一个静态成员函数,这里值得一提的是,静态的成员函数没有隐含的this指针,因此外界可以通过类名加域的访问符号::来调用静态的成员函数

类的成员变量只定义了一个指向类对象的一个_instance指针,静态的成员函数可以在类外部初始化,先将其初始化为NULL,当第一次调用这个GetInstance函数的时候,_instance为NULL,因此为其分配一个类对象的空间并将其返回;但是当第二次调用这个函数的时候,_instance已经有了值并不会再分配空间而是返回已经存在的实例化出的对象,因此无论怎么调用GetInstance函数都只会返回同一块地址空;

但是上面的函数在单线程环境下运行是没有问题的,当有多个线程并发访问这个函数的时候,如果两个或多个线程同时拿到了初始化为NULL的_instance的值要进行判断的时候,有可能都会判断成功,也就是会new出来两块不同的地址空间,这样就不符合设计的初衷了,因此在多线程运行环境下,GetInstance函数中的代码就会成为临界区,也就是要有互斥的关系,可以为其加上mutex互斥锁:

static Singleton*& GetInstance()
{
    pthread_mutex_lock(&lock);
    if(_instance == NULL)
    {
        _instance = new Singleton();
    }
    pthread_mutex_unlock(&lock);
    return _instance;
}

可是上面的代码还是存在一些效率的问题,如果一个线程最开始获得了锁并且成功new出了空间,那么之后的线程每一次进到函数GetInstance里面都要争夺一下锁资源并且再依次判断,所以,可以在加锁之前就先进行一次判断,如果_instance不为空,后面就没有必要竞争锁资源再进行判断了,所以代码可以优化为如下:

static Singleton*& GetInstance()
{
    if(_instance == NULL)
    {
        pthread_mutex_lock(&lock);
        if(_instance == NULL)
        {
            _instance = new Singleton();
        }
        pthread_mutex_unlock(&lock);
    }
    return _instance;
}

其实除了上面所给出的解法,还有另外一种简单粗暴的设计方式,那就是直接在给静态成员变量_instance初始化的时候就初始化为new出来的一个类的实例化对象,之后每一次调用GetInstance函数获取_instance的值的时候就直接返回:

class Singleton
{
private:
    Singleton()
    {}  
    Singleton(Singleton& s); 
    Singleton& operator=(Singleton& s); 

public:
    static Singleton*& GetInstance()
    {   
        return _instance;
    }   

private:
    static Singleton *_instance;
};
Singleton* Singleton::_instance = new Singleton();

上面一次性就将对象空间给开辟出来每次不用判断就直接返回,这种方式被称为饿汉式,相当于用空间换时间;而前面一种在需要的时候去判断然后开辟空间,这种方式被叫做懒汉式,就相当于用时间来换空间了,各有利弊。

《完》

时间: 2024-07-28 17:12:33

C++中的单例模式——2的相关文章

“只生一个娃”--设计模式中的单例模式

"只生一个娃"–设计模式中的单例模式(Singleton) 引言 ??被人问到什么是单例模式,突然回答不上来,似乎印象不深了.回去补了一下功课,突然明白了,原来在项目中一直使用的日志模块即采用了单例模式,只是熟视无睹,没有意识到罢了. ??所谓单例模式(Singleton),即指一个类只有一个实例(Instance),并给外界提供访问该实例的一个全局访问点. ??通常我们可以使用全局变量的方式来实现"只生一个娃",但更好的方法就是:让该类自身负责创建和保存它的唯一实

JAVA中的单例模式(采用单例模式定义的类)(转)

1     单例(Singleton)模式:单例模式确保某一个类只有一个 实例,而且该类只能是自己 实例化自己并向其他类公开 这个实例的对象创建 模式 采用单例模式的类:根据单例模式知道其要满足以下三点 1. 确保某一个类只有一个实例 2. 而且自己实例化 3. 并向其他类提供这个实例类 . 2    确保以上三点的所采用的编程策略     * 把构造方法声明为Private.确保只能由自己创建,避免外部创建实例或者被子类继承从而创造额外实例:    * 定义一个私有静态的该类的实例作为该类的数

iOS中的单例模式

单例模式的优点: 由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁地创建.销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显了. 由于单例模式只生成一个实例,所以减少了系统的性能开销,当一个对象的产生需要比较多的资源时,如读取配置.产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后用永久驻留内存的方式来解决. 单例模式可以避免对资源的多重占用,例如一个写文件动作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作. 单例模式可以在

C# 中实现单例模式

文章目录 简介 不安全线程的单例模式 简单安全线程带锁 双重检查 - 带锁 安全初始化 安全并且懒汉式静态初始化 带泛型的懒汉式单例 异常 提高效率 总结 简介 单例模式是软件工程中广为人知的设计模式.单例模式就是指一个永远只能实例化一次.使用的方式是调用类里创建的静态方法.通常来说,单例模式创建的类,都是不带形参的 ,原因就是当创建多个实例的时候,如果参数不同的话(比如2个不同的重载构造函数),那么就会造成一些不必要的问题(如果相同的实例要被创建而且他们使用相同的参数的话,那么建议使用工厂模式

Objective-C中的单例模式

?单例模式算是设计模式中比较简单的一种吧,设计模式不是只针对某种编程语言,在C++, Java, PHP等其他OOP语言也有设计模式,笔者初接触设计模式是通过<漫谈设计模式>了解的.这本书中是用java写的,个人感觉拜读完这本书以后虽然有不理解的地方但还是收获蛮大的.上面提到依赖注入,控制翻转的时候,没大看懂,当学习到Strut,Spring, Hibernate的东西的时候才略懂略懂.不过在23种设计模式里面单例模式还是算比较好理解的, 那么在OC中又是怎么来表示单例模式的呢?下面会结合着代

java中的单例模式与静态类

单例模式与静态类(一个类,所有方法为静态方法)是另一个非常有趣的问题,在<Java中有关单例模式的面试问题>博文中露掉了,由于单例模式和静态类都具有良好的访问性,它们之间有许多相似之处,例如,两者可以直接使用而无须创建对象,都可提交唯一实例,在一个非常高的高度上看起来它们都为是用于同样的任务.由于它们具有较多的相似性,面试官常常会问一些类似为神马使用单例模式替换静态方法?你能使用静态类替换单例模式吗?Java中单例模式与静态的区别有那些?等这样的问题,为回答这些问题,记住他们单例模式和静态方法

Java中的单例模式

Java中的单例模式分为两种:懒汉模式和饿汉模式 懒汉模式代码: 类加载快,在运行时获取对象进度慢 private static Student stu; //创建一个私有的静态学生类对象 private Student(){} //把构造数改成私有的 //单线程 /* public static Student getInstance(){ if(stu==null) // 为空就new一个空间 { stu=new Student(); } return stu; }*/ //双线程 publ

在ios中使用单例模式编程

本文转载至 http://blog.csdn.net/remote_roamer/article/details/7107007 1.    @implementation Singleton    2.         3.    + (Singleton *)instance  {    4.            static Singleton *instance;    5.               6.            @synchronized(self) {    7.

C++中的单例模式

最近遇到几道类似的笔试题: 1. 请实现一个单例模式的类,要求线程安全. 2. 用C++设计一个不能被继承的类. 3. 如何定义一个只能在堆上(栈上)生成对象的类? 这些题目本质上都跟单例模式相关. 单例模式 单例模式就是保证一个类只有一个实例,并提供一个访问它的全局访问点.首先,需要保证一个类只有一个实例:在类中,要构造一个实例,就必须调用类的构造函数,如此,为了防止在外部调用类的构造函数而构造实例,需要将构造函数的访问权限标记为protected或private:最后,需要提供要给全局访问点

C++中的单例模式(转)

单例模式也称为单件模式.单子模式,可能是使用最广泛的设计模式.其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享.有很多地方需要这样的功能模块,如系统的日志输出,GUI应用必须是单鼠标,MODEM的联接需要一条且只需要一条电话线,操作系统只能有一个窗口管理器,一台PC连一个键盘.       单例模式有许多种实现方法,在C++中,甚至可以直接用一个全局变量做到这一点,但这样的代码显的很不优雅. 使用全局对象能够保证方便地访问实例,但是不能保证只声明一个对象——