• 单例模式


    单例模式的写法总的来说分为两类:饿汉式和饱汉式,他们都依赖C++的一个知识点:static的使用。

    具体的写法有很多种,首先给出最推荐的写法。这个写法是所谓的饱汉式(即:延时初始化,再使用的时候才去初始化)

    复制代码
    class Singleton
    {
    public:
        static Singleton& getInstance() {
            static Singleton _instance;
            return _instance;
        }
        Singleton(const Singleton& other) = delete;
        Singleton(Singleton&& other) = delete;
        Singleton& operator=(const Singleton& other) = delete;
        Singleton&operator=(Singleton&& other) = delete;
        
    private:
        Singleton() = default;
        ~Singleton() = default;
    };
    复制代码

    也看到过有人这样写,我觉得没有必要。

    复制代码
    class Singleton
    {
    public:
        static Singleton* getInstance() {
            static Singleton _instance;
            return &_instance;
        }
        Singleton(const Singleton& other) = delete;
        Singleton(Singleton&& other) = delete;
        Singleton& operator=(const Singleton& other) = delete;
        Singleton&operator=(Singleton&& other) = delete;
        
    private:
        Singleton() = default;
        ~Singleton() = default;
    };
    复制代码

     

    下面给出其他的写法

    写法一:静态成员饿汉式

    存在的问题:no local static(函数外的static)变量在不同的编译单元中的初始化顺序未定义,即static Singleton& getInstance()和static Singleton _instance的顺序未知。

    复制代码
    class Singleton
    {
    public:
        static Singleton& getInstance() {
            return _instance;
        }
        Singleton(const Singleton& other) = delete;
        Singleton(Singleton&& other) = delete;
        Singleton& operator=(const Singleton& other) = delete;
        Singleton& operator=(Singleton&& other) = delete;
    
    private:
        static Singleton _instance;
        Singleton() = default;
        ~Singleton() = default;
    };
    Singleton Singleton::_instance;
    复制代码

     

    写法二:指针饱汉式

    存在的问题:1.不是线程安全(改进:加锁)、2.内存泄漏(改进:使用智能指针或者依赖静态的嵌套类的析构函数)

    复制代码
    class Singleton
    {
    public:
        static Singleton* getInstance() {
            if (_instance)
                _instance = new Singleton();
            return _instance;
        }
        Singleton(const Singleton& other) = delete;
        Singleton(Singleton&& other) = delete;
        Singleton& operator=(const Singleton& other) = delete;
        Singleton& operator=(Singleton&& other) = delete;
    
    private:
        static Singleton *_instance;
        Singleton() = default;
        ~Singleton() = default;
    };
    Singleton* Singleton::_instance = nullptr;
    复制代码

     

    题外话:

    写法二中的指针到底需不需要释放?

    如果对象没有被释放,在程序运行期间可能会存在内存泄露问题。

    有人可能会说,在程序结束时,操作系统会进行必要的清理工作,包括释放进程的所有堆栈等信息,即使存在内存泄露,操作系统也会收回的;且对于单例来讲,进程运行期间仅有一个,对于现代计算机而言,占用的内存貌似也不会太大。而且该实例有可能根本就没有进行内存的申请操作,这种情况下不释放实例所占内存,对进程的运行也不会造成影响。

    但我觉得还是要在合适的地方加上释放(在哪儿合适呢,在程序关闭前?),养成良好的习惯,并且对于大型项目来说,会有内存检测工具,避免报内存泄漏,增加检查成本。

     当然,如果采用前面的最佳模式,就无需考虑这个问题了,只需要写好这个类的析构函数就可以了。

  • 相关阅读:
    Javascript知识【jQuery:操作内容】
    uboot引导应用程序
    随笔-北漂之旅启程
    @RequiredArgsConstructor 引发的循环依赖问题
    二、Rocketmq-dashboard的web管理页面部署
    静态HTML旅行主题网页设计与实现——联途旅游网服务平台网(39页)HTML+CSS+JavaScript
    TCP/IP、DTN网络通信协议族
    【考研】操作系统——同步互斥问题(P、V操作)2
    企事业单位/公司电脑文件透明加密保护 | 防泄密软件\系统!
    记录一下工作中completableFutures异步多线程的使用
  • 原文地址:https://www.cnblogs.com/hosseini/p/18146328