C++单例模式

1.什么是单例模式?

  单例模式也称为单件模式、单子模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类,即设计的一个类成为单例。通过单例模式可以保证系统中一个这个类只有一个实例。即一个类只有一个对象实例。(设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结)。单例模式是设计模式中最简单的形式之一。用一种只允许生成对象类的唯一实例的机制,“阻止”所有想要生成对象的访问。使用工厂方法来限制实例化过程。这个方法应该是静态方法(类方法),因为让类的实例去生成另一个唯一实例毫无意义。

2.设计单例模式要点

目标功能:一是设计某个类且只能有一个实例;二是这个类必须自行创建这个实例;三是类必须自行向整个系统提供这个实例。保证全局只有一个唯一实例对象;提供获取这个唯一实例的接口。

具体实现要点:一是单例模式的类只提供私有的构造函数;二是类定义中含有一个该类的静态私有对象,三是该类提供了一个静态的公有的函数用于创建或获取它本身的静态私有对象(只能在类里创建对象)。

  单例模式通过类本身来管理其唯一实例,这种特性提供了解决问题的方法。唯一的实例是类的一个普通对象,但设计这个类时,让它只能创建一个实例并提供对此实例的全局访问。唯一实例类Singleton在静态成员函数中隐藏创建实例的操作。习惯上把这个成员函数叫做GetInstance(),它的返回值是唯一实例的指针。

3.优缺点

优点:

(1)实例控制:单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。

(2)灵活性:因为类控制了实例化过程,所以类可以灵活更改实例化过程。

缺点:

(1)开销:虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。

(2)可能的开发混淆:使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。

(3)对象生存期:不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用。。

4.两种实现方式

(1)懒汉模式 ---lazy load + 相对而言 复杂--各种场景下都适用

//设计一个类,成为单例
class Lock  //自造轮子
{
public:
    //RAII思想
    Lock(mutex& mx)
        :_mx(mx)
    {
        _mx.lock();
    }
    ~Lock()
    {
        _mx.unlock();
    }
private:
    Lock(const Lock&);
    Lock& operator=(const Lock&);

    mutex& _mx;
};
//懒汉模式
class Singleton
{
public:
    //1.获取本身静态私有对象的静态成员函数
    static Singleton* GetInstance()
    {
        if (_inst == NULL) {
            //加锁(防死锁)-->线程安全
            //lock_guard<mutex> lock(_mtx);
            Lock lock(_mtx);

            Singleton* tmp = new Singleton;

            //双检查
            MemoryBarrier();
            _inst = tmp;
        }
        return _inst;
    }

    static void DelInstance()
    {
        lock_guard<mutex> lock(_mtx);
        if (_inst)
        {
            cout << "delete" << endl;
            delete _inst;
            _inst = NULL;

        }
    }
    struct GC
    {
        ~GC()
        {
            DelInstance();
        }
    };

    void Print()
    {
        cout << "Singleton:" << _a << endl;
    }
private:
    //2.构造函数定义为私有
    Singleton()
        :_a(0)
    {}
    ~Singleton()
    {}

    //防拷贝
    Singleton(const Singleton&);
    Singleton& operator=(const Singleton&);

    int _a;

    //3.静态私有对象
    static Singleton* _inst;

    static mutex _mtx;
};
Singleton* Singleton::_inst = NULL;
mutex Singleton::_mtx;
static Singleton::GC gc;

void Test()
{
    Singleton::GetInstance()->Print();
    Singleton::GetInstance()->Print();
    Singleton::GetInstance()->Print();
    Singleton::GetInstance()->Print();
    Singleton::GetInstance()->Print();
}

  用户访问唯一实例的方法只有GetInstance()成员函数。如果不通过这个函数,任何创建实例的尝试都将失败,因为类的构造函数是私有的。GetInstance()使用懒惰初始化,也就是说它的返回值是当这个函数首次被访问时被创建的。这是一种防弹设计——所有GetInstance()之后的调用都返回相同实例的指针:
Singleton* p1 = Singleton :: GetInstance();
Singleton* p2 = p1->GetInstance();
Singleton & ref = * Singleton :: GetInstance();
对GetInstance稍加修改,这个设计模板便可以适用于可变多实例情况。

关于Singleton(const Singleton);和 Singleton & operate = (const Singleton&);函数,需要声明成私有的,并且只声明不实现。这样,如果用上面的方式来使用单例时,不管是在友元类中还是其他的,编译器都是报错。考虑到线程安全、异常安全用了锁。

注:上述实现的单例属于 "懒汉模式"的单例。即:都采取的是用时间换空间的思想。

(2)饿汉模式  ----一开始(main) load  简洁 适用性会受到限制 动态库

//饿汉模式
class Singleton2
{
public:
    //1.获取本身静态私有对象的静态成员函数
    static Singleton2 GetInstance()
    {
        assert(_inst);
        return *_inst;
    }
    
    void Print()
    {
        cout << "Singleton:" << _a << endl;
    }

private:
    //2.构造函数定义为私有
    Singleton2()
        :_a(0)
    {}
    
    //防拷贝
    Singleton2(const Singleton2&);
    Singleton2& operator=(const Singleton2&);

    int _a;
    //3.静态私有对象
    static Singleton2* _inst;

};
  // 外部初始化(进入主函数之前)
    const Singleton* Singleton::pInstance = new _inst;
    void Test()
    {
        Singleton::GetInstance().Print();
        Singleton::GetInstance().Print();
        Singleton::GetInstance().Print();
    }

这是一种较简单的实现方式,但问题也较多,应用用不太广泛。第一种方法可适用于各种复杂情况下。

注意:静态实例初始化保证了线程安全。

REASON:静态实例初始化在程序开始时进入主函数之前就由主线程以单线程方式完成了初始化。可以不用考虑多线程的问题。因此这种模式在性能需求较高时,可避免频繁的锁竞争。

两种模式的区别:饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变,线程安全。所以加载类时比较慢,但运行时获取对象的速度比较快。懒汉模式在程序运行时创建实例对象,线程不安全,需要加锁。但加载类时比较快,而在运行时获取对象的速度比较慢,所以推荐使用饿汉模式。

通俗来讲就是懒汉式是在你真正需要使用实例对象时才去创建这个单例对象;饿汉式不管你用不用都先给你创建这个单例对象。

4.单例的应用广泛

  对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在现有省、市港口信息化系统进行有效整合基础上,借鉴新 一代的感知-传输-应用技术体系,实现对码头、船舶、货物、重 大危险源、危险货物装卸过程、航管航运等管理要素的全面感知、 有效传输和按需定制服务,为行政管理人员和相关单位及人员提 供高效的管理辅助,并为公众提供便捷、实时的水运信息服务。 建立信息整合、交换和共享机制,建立健全信息化管理支撑 体系,以及相关标准规范和安全保障体系;按照“绿色循环低碳” 交通的要求,搭建高效、弹性、高可扩展性的基于虚拟技术的信 息基础设施,支撑信息平台低成本运行,实现电子政务建设和服务模式的转变。 实现以感知港口、感知船舶、感知货物为手段,以港航智能 分析、科学决策、高效服务为目的和核心理念,构建“智慧港口”的发展体系。 结合“智慧港口”相关业务工作特点及信息化现状的实际情况,本项目具体建设目标为: 一张图(即GIS 地理信息服务平台) 在建设岸线、港口、港区、码头、泊位等港口主要基础资源图层上,建设GIS 地理信息服务平台,在此基础上依次接入和叠加规划建设、经营、安全、航管等相关业务应用专题数据,并叠 加动态数据,如 AIS/GPS/移动平台数据,逐步建成航运管理处 "一张图"。系统支持扩展框架,方便未来更多应用资源的逐步整合。 现场执法监管系统 基于港口(航管)执法基地建设规划,依托统一的执法区域 管理和数字化监控平台,通过加强对辖区内的监控,结合移动平 台,形成完整的多维路径和信息追踪,真正做到问题能发现、事态能控制、突发问题能解决。 运行监测和辅助决策系统 对区域港口与航运业务日常所需填报及监测的数据经过科 学归纳及分析,采用统一平台,消除重复的填报数据,进行企业 输入和自动录入,并进行系统智能判断,避免填入错误的数据, 输入的数据经过智能组合,自动生成各业务部门所需的数据报 表,包括字段、格式,都可以根据需要进行定制,同时满足扩展 性需要,当有新的业务监测数据表需要产生时,系统将分析新的 需求,将所需字段融合进入日常监测和决策辅助平台的统一平台中,并生成新的所需业务数据监测及决策表。 综合指挥调度系统 建设以港航应急指挥中心为枢纽,以各级管理部门和经营港 口企业为节点,快速调度、信息共享的通信网络,满足应急处置中所需要的信息采集、指挥调度和过程监控等通信保障任务。 设计思路 根据项目的建设目标和“智慧港口”信息化平台的总体框架、 设计思路、建设内容及保障措施,围绕业务协同、信息共享,充 分考虑各航运(港政)管理处内部管理的需求,平台采用“全面 整合、重点补充、突出共享、逐步完善”策略,加强重点区域或 运输通道交通基础设施、运载装备、运行环境的监测监控,完善 运行协调、应急处置通信手段,促进跨区域、跨部门信息共享和业务协同。 以“统筹协调、综合监管”为目标,以提供综合、动态、实 时、准确、实用的安全畅通和应急数据共享为核心,围绕“保畅通、抓安全、促应急"等实际需求来建设智慧港口信息化平台。 系统充分整合和利用航运管理处现有相关信息资源,以地理 信息技术、网络视频技术、互联网技术、移动通信技术、云计算 技术为支撑,结合航运管理处专网与行业数据交换平台,构建航 运管理处与各部门之间智慧、畅通、安全、高效、绿色低碳的智 慧港口信息化平台。 系统充分考虑航运管理处安全法规及安全职责今后的变化 与发展趋势,应用目前主流的、成熟的应用技术,内联外引,优势互补,使系统建设具备良好的开放性、扩展性、可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值