C++设计模式:单例模式(饿汉式、懒汉式)

单例模式是什么?

单例模式是一种创建型的软件设计模式。通过单例模式的设计,使得创建的类在当前进程中只有唯一一个实例,并提供一个全局性的访问点,这样可以规避因频繁创建对象而导致的内存飙升情况。

单例模式有三个要点

  • 私有化构造函数:这样外界就无法自由地创建类对象,进而阻止了多个实例的产生。
  • 类定义中含有该类的唯一静态私有对象:静态变量存放在全局存储区,且是唯一的,供所有对象使用。
  • 用公有的静态函数来获取该实例:提供了访问接口。

基础代码 

 h文件:

//
// Created by qiaowei on 2023-12-25.
//

#ifndef RADARDATACONTROLLER_MAIN_WINDOW_HANDLER_H
#define RADARDATACONTROLLER_MAIN_WINDOW_HANDLER_H

#include <QObject>

namespace handler {

    class MainWindowHandler : public QObject{

    public:
        virtual ~MainWindowHandler() override;

        static MainWindowHandler* instance();

    private:
        explicit MainWindowHandler(QObject* parent = nullptr);

    private:
        /**
         * @date   2023-12-25 19:32
         * @author qiao wei
         * @brief  MainwindowHandler实例指针。static函数只能访问静态成员变量或函数,所以必须为static
         */
        static MainWindowHandler* instance_;
    };

} // handler

#endif //RADARDATACONTROLLER_MAIN_WINDOW_HANDLER_H

cpp文件:

//
// Created by qiaowei on 2023-12-25.
//

#include "main_window_handler.h"

namespace handler {

    // 静态非const整型成员变量必须在类外定义。
    MainWindowHandler* MainWindowHandler::instance_ = nullptr;

    MainWindowHandler::MainWindowHandler(QObject* parent) : QObject(parent) {}

    MainWindowHandler::~MainWindowHandler() {}

    MainWindowHandler* MainWindowHandler::instance() {
        if (nullptr == instance_) {
            instance_ = new MainWindowHandler{nullptr};
        }

        return instance_;
    }

} // handler

单例模式一般分为懒汉式和饿汉式。

单例模式的基础代码不符合线程安全,因此引出了懒汉式和饿汉式单例模式。懒汉式:指全局的单例实例在第一次被使用时构建。饿汉式:全局的单例实例在类装载(ClassLoader)时构建(饿汉式单例性能优于懒汉式单例)。

懒汉式和饿汉式的区别:

  • 懒汉式默认不会实例化,外部什么时候调用什么时候new。饿汉式在类加载的时候就实例化,并且创建单例对象。
  • 懒汉式是延时加载,在需要的时候才创建对象,而饿汉式是在虚拟机启动的时候就会创建。
  • 懒汉式在多线程中是线程不安全的,而饿汉式是不存在多线程安全问题的。

懒汉单例模式(需要时再实例化单例对象)

 懒汉模式中使用QMutex,QMutexLocker进行同步锁。

h文件:

//
// Created by qiaowei on 2023-12-25.
//

#ifndef RADARDATACONTROLLER_MAIN_WINDOW_HANDLER_H
#define RADARDATACONTROLLER_MAIN_WINDOW_HANDLER_H

#include <QObject>

namespace handler {

    class MainWindowHandler : public QObject{

    public:
        /**
         * @date    2023-12-25 21:54
         * @author  qiao wei
         * @version 1.0
         * @brief   拷贝构造函数。删除拷贝构造,防止对象通过拷贝构造创建对象。
         * @param
         * @return
         * @throws
         */
        MainWindowHandler(const MainWindowHandler& value) = delete;

        virtual ~MainWindowHandler() override;

        /**
         * @date    2023-12-25 21:56
         * @author  qiao wei
         * @version 1.0
         * @brief   赋值操作符。删除赋值操作符,防止简单类型通过赋值创建对象。
         * @param
         * @return
         * @throws
         */
        MainWindowHandler& operator=(const MainWindowHandler& value) = delete;

        /**
         * @date    2023-12-25 21:47
         * @author  qiao wei
         * @version 1.0
         * @brief   返回MainWindowHandler*指针的static函数。
         * @param
         * @return  Mainwindow*指针。
         * @throws
         */
        static MainWindowHandler* instance();

    private:
        explicit MainWindowHandler(QObject* parent = nullptr);

    private:
        /**
         * @date   2023-12-25 19:32
         * @author qiao wei
         * @brief  MainwindowHandler实例指针。
         */
        static MainWindowHandler* instance_;

        static QMutex mutex_;
    };

} // handler

#endif //RADARDATACONTROLLER_MAIN_WINDOW_HANDLER_H

cpp文件:

//
// Created by qiaowei on 2023-12-25.
//

#include <QMutexLocker>
#include <QMutex>
#include "main_window_handler.h"

namespace handler {

    // 静态成员在类外初始化。
    MainWindowHandler* MainWindowHandler::instance_ = nullptr;
    QMutex MainWindowHandler::mutex_;

    MainWindowHandler::~MainWindowHandler() {
        delete instance_;
        instance_ = nullptr;
    }

    MainWindowHandler* MainWindowHandler::instance() {
        // 第1次检查:实例化单例对象后,就不会再进入加锁逻辑。
        if (nullptr == instance_) {
            // 加同步锁。
            QMutexLocker mutex_locker(&mutex_);

            // 第2次检查:可能2个线程同时通过第1次检查,1个线程获得锁时,可能另外1个线程已经实例化单体。
            if (nullptr == instance_) {
                instance_ = new MainWindowHandler{nullptr};
            }
        }

        return instance_;
    }

    MainWindowHandler::MainWindowHandler(QObject* parent) : QObject(parent) {}

} // handler

饿汉单例模式(一开始就初始化单例对象)

饿汉模式一

饿汉模式一缺点:不会调用析构函数,需要手动delete。

h文件

//
// Created by qiaowei on 2023-12-25.
//

#ifndef RADARDATACONTROLLER_EAGER_SINGLETON_H
#define RADARDATACONTROLLER_EAGER_SINGLETON_H

#include <QObject>

namespace handler {

    class EagerSingleton : public QObject{

    public:
        virtual ~EagerSingleton() override;

        static EagerSingleton* instance();

    private:
        explicit EagerSingleton(QObject* parent = nullptr);

    private:
        static EagerSingleton* instance_;
    };

} // handler

#endif //RADARDATACONTROLLER_EAGER_SINGLETON_H

cpp文件

//
// Created by qiaowei on 2023-12-25.
//

#ifndef RADARDATACONTROLLER_EAGER_SINGLETON_H
#define RADARDATACONTROLLER_EAGER_SINGLETON_H

#include <QObject>

namespace handler {

    class EagerSingleton : public QObject{

    public:
        virtual ~EagerSingleton() override;

        static EagerSingleton* instance();

    private:
        explicit EagerSingleton(QObject* parent = nullptr);

    private:
        static EagerSingleton* instance_;
    };

} // handler

#endif //RADARDATACONTROLLER_EAGER_SINGLETON_H

饿汉模式二

h文件

//
// Created by qiaowei on 2023-12-25.
//

#ifndef RADARDATACONTROLLER_EAGER_SINGLETON_2_H
#define RADARDATACONTROLLER_EAGER_SINGLETON_2_H

#include <QObject>

namespace handler {

    class EagerSingleton2 : public QObject{

    public:
        static EagerSingleton2* instance();

        virtual ~EagerSingleton2();

    private:
        explicit EagerSingleton2(QObject* parent = nullptr);

    private:
        static EagerSingleton2 eager_singleton_;
    };

} // handler

#endif //RADARDATACONTROLLER_EAGER_SINGLETON_2_H

cpp文件

//
// Created by qiaowei on 2023-12-25.
//

#include "eager_singleton_2.h"

namespace handler {

    EagerSingleton2 EagerSingleton2::eager_singleton_;

    EagerSingleton2* EagerSingleton2::instance() {
        return &eager_singleton_;
    }

    EagerSingleton2::~EagerSingleton2() {}

    EagerSingleton2::EagerSingleton2(QObject *parent) : QObject(parent) {}

} // handler

饿汉模式总结:

由于在定义静态变量的时候实例化单例类,因此在类加载的时候就已经创建了单例对象,可确保单例对象的唯一性。

饿汉模式缺点:

无论系统运行时是否需要使用该单例对象,都会在类加载时创建对象,资源利用效率不高。

相关推荐

  1. C++设计模式模式饿懒汉

    2023-12-27 08:38:02       60 阅读
  2. 设计模式-模式饿

    2023-12-27 08:38:02       33 阅读
  3. 设计模式 | 模式 | 懒汉&饿

    2023-12-27 08:38:02       43 阅读
  4. 模式 饿懒汉的区别

    2023-12-27 08:38:02       26 阅读
  5. 饿模式

    2023-12-27 08:38:02       35 阅读
  6. 模式饿

    2023-12-27 08:38:02       32 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2023-12-27 08:38:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2023-12-27 08:38:02       100 阅读
  3. 在Django里面运行非项目文件

    2023-12-27 08:38:02       82 阅读
  4. Python语言-面向对象

    2023-12-27 08:38:02       91 阅读

热门阅读

  1. 【数据库】postgressql设置数据库执行超时时间

    2023-12-27 08:38:02       61 阅读
  2. 黑客常用端口利用总结

    2023-12-27 08:38:02       42 阅读
  3. python之列表动态生成和重复数据处理

    2023-12-27 08:38:02       60 阅读
  4. VSCode 加Cortex-Debug嵌入式调试方法

    2023-12-27 08:38:02       53 阅读
  5. codeforces 1904B

    2023-12-27 08:38:02       58 阅读
  6. 单例模式你了解嘛?

    2023-12-27 08:38:02       50 阅读
  7. Mac_通过chmod处理文件权限

    2023-12-27 08:38:02       44 阅读
  8. 处理go中clientv3连接etcd包异常

    2023-12-27 08:38:02       54 阅读
  9. AWS的EC2之间ping不通,服务之间不通,怎么办

    2023-12-27 08:38:02       49 阅读
  10. 2023-全国智能驾驶测试赛-车联网安全专项赛WP (Re)

    2023-12-27 08:38:02       44 阅读