单例模式(C++实现)

一、什么是单例模式

1.1单例模式的基本概念

    单例模式属于创建型模式,这种模式涉及到一种单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一对象的方式。
    单例类的特征:1.单例类最多只能有一个实例;2.单例类必须自己创建自己唯一的实例;3.单例类必须给所有其他的对象提供这一实例。

1.2使用单例模式的好处

    使用单例类是为了保证某一个类仅有一个实例,并提供一个访问它的全局访问点。
    单例类主要解决了一个全局使用的类的频繁的创建与销毁。
    所以单例模式有以下几个优点: 1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例;2、避免对资源的多重占用。
    那单例模式有一个不好的地方就是,单例类没有接口,不能继承。

1.3单例模式的使用场景

    当我们想在程序中控制实例数目,节约系统资源的时候,可以考虑使用单例类。
    >>1.Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。
    >>2.一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件。

二、单例模式的C++实现

2.1懒汉式

    什么叫懒汉式的单例类呢?顾名思义,懒汉很懒,只有他饿了的时候才会去找吃的,也就是说只有在需要的时候才会去实例化。一次都没有需要的时候,不会去构造这个对象,这个程序中也就没有这个对象的实例,只有需要了一次了,实例化了一次,这个对象才会一直存在。

//Singleton.cpp
#include<iostream>
#include<mutex>
using namespace std;
//mutex singletonLock;
class Singleton {
public:
    static Singleton* getInstance() {
        static Singleton* singeltonInstance;//函数内的静态变量,声明加定义,已分配空间。
        cout << "getInstance in singleton." << endl;
//线程安全
        //if(singeltonInstance == NULL){
        //  singletonLock.lock();//线程安全
            if (singeltonInstance == NULL)
              singeltonInstance = new Singleton();
       //   singletonLock.unlock();
       //}
        return singeltonInstance;
    };
private:
    //static Singleton* singeltonInstance;//若在此处定义,类内的静态成员变量,要记得在类外部的cpp文件的全局进行初始化。(仅仅是声明,并没定义,所以没有分配空间)
//Static members obey the usual class member access rules (clause 11). When used in the declaration of a class member, the static specifier shall only be used in the member declarations that appear within the member-specification of the class declaration. [Note: it cannot be specified in memberdeclarations that appear in namespace scope. ] 
    Singleton() {
        cout << "Construct in singleton." << endl;
    }
    Singleton(const Singleton&);//拷贝构造函数和赋值运算符也是私有的,以禁止拷贝和赋值;
    Singleton& operator=(const Singleton&);
};

    
    懒汉式的单例类在多线程的使用中存在线程安全问题。如果有两个线程同时获取单例类的实例,又都发现实例不存在,因此都会进行实例化,会产生两个实例都要赋给singeltonInstance,会造成严重的错误,要解决这个问题就要加锁。上面程序注释掉的为线程安全的部分,即为懒汉式单例模式线程安全问题的一个解决方案。

2.2饿汉式

    饿汉式的单例类,会在全局作用域进行单例类的实例化,并以此来初始化。

//Singleton.cpp
#include<iostream>
using namespace std;
class Singleton;
class Singleton {
private:
    Singleton() {};//构造函数私有化
    Singleton(Singleton &s) {}; //拷贝构造私有化
    Singleton& operator=(const Singleton& s) {};
    static Singleton* singletonInstance;
public:
    static Singleton* getInstance() {
        return singletonInstance;
    }
};
//......
Singleton* Singleton::singletonInstance = new Singleton();//全局实例化

2.3 单例模式的GC

    1.单例模式中实例化的对象是new出来的,需要对它负责,也就是需要delete;
    2.delete一个对象时,会调用它的析构函数;
    3.如果在析构函数里使用delete进行内存管理,由于对象是new出来的,根本进不去析构函数,无法自动的销毁;
    4.如果在析构函数里使用delete进行内存管理,就一定会造成一个析构的循环的(见2)。

    那么应该怎样在C++的程序中显式的进行单例对象的内存管理呢?一个比较好的方法是定义一个内部垃圾回收类,并且在Singleton中定义一个此类的静态成员。程序结束时,系统会自动析构此静态成员,此时,在此类的析构函数中析构Singleton实例,就可以实现singletonInstance的自动释放。

//Singleton.cpp
#include<iostream>
using namespace std;
class Singleton;
class Singleton {
private:
    Singleton() { cout << "Construct singleton." << endl; };//构造函数私有化
    Singleton(Singleton &s) {}; //拷贝构造私有化
    Singleton& operator=(const Singleton& s) {};
    static Singleton* singletonInstance;

    class SingletonCG {//单例的回收
    public:
        ~SingletonCG(){
            if (singletonInstance != NULL)
                delete singletonInstance;
            singletonInstance = NULL;
            cout << "Singleton delete." << endl;
            system("pause");
        }
    };
    static SingletonCG cg;
public:
    static Singleton* getInstance() {
        cout << "getInstance." << endl;
        return singletonInstance;
    }
    
};
//......
Singleton* Singleton::singletonInstance = new Singleton();//全局实例化
Singleton::SingletonCG Singleton::cg;////类的静态成员需要类外部初始化,这一点很重要,否则程序运行连GC的构造都不会进入,何谈自动析构

三、使用单例模式的注意事项

四、参考资料

[1]单例模式——菜鸟教程
[2]单例模式——C++实现
[3]单例模式——C++的GC

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,193评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,306评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,130评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,110评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,118评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,085评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,007评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,844评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,283评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,508评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,395评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,985评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,630评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,797评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,653评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,553评论 2 352

推荐阅读更多精彩内容