C++单例模式与多例模式

news2024/11/15 5:25:39

C++ 单例模式的设计意图

单例模式(Singleton Pattern) 是一种创建型设计模式,其主要目的是确保一个类只有一个实例,并提供一个全局访问点。单例模式常用于需要全局唯一实例的场景,例如:

  1. 日志记录器:在整个应用程序中,只需要一个日志记录器实例来记录所有的日志信息。
  2. 配置管理器:应用程序的配置信息通常只需要一个实例来管理。
  3. 数据库连接池:在整个应用程序中,只需要一个数据库连接池实例来管理数据库连接。

单例模式的实现方式

单例模式的实现方式主要有两种:懒汉式(Lazy Initialization) 和 饿汉式(Eager Initialization)

懒汉型单例模式

懒汉式单例模式在第一次使用时才创建实例,因此它具有延迟加载的特性。如果单例对象的创建成本较高,懒汉式可以在需要时才进行创建,从而提高性能。

#include <iostream>
#include <mutex>

class Singleton {
private:
    static Singleton* instance;
    static std::mutex mtx;

    // 构造函数私有化,防止外部创建实例
    Singleton() {
        std::cout << "Singleton instance created." << std::endl;
    }

public:
    // 获取单例实例
    static Singleton* getInstance() {
        // 双重检查锁定,确保线程安全
        if (instance == nullptr) {
            std::lock_guard<std::mutex> lock(mtx);
            if (instance == nullptr) {
                instance = new Singleton();
            }
        }
        return instance;
    }

    // 删除拷贝构造函数和赋值运算符,防止拷贝
    Singleton(Singleton const&) = delete;
    Singleton& operator=(Singleton const&) = delete;

    // 销毁实例
    static void destroyInstance() {
        delete instance;
        instance = nullptr;
    }

    // 测试方法
    void showMessage() {
        std::cout << "Hello from Singleton!" << std::endl;
    }
};

// 静态成员变量初始化
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();

    s1->showMessage();
    s2->showMessage();

    if (s1 == s2) {
        std::cout << "s1 and s2 are the same instance." << std::endl;
    } else {
        std::cout << "s1 and s2 are different instances." << std::endl;
    }

    Singleton::destroyInstance();
    return 0;
}

饿汉型单例模式

饿汉式单例模式在程序启动时就创建实例,而不是在第一次使用时创建。由于实例在程序启动时就创建,因此它的实现相对简单,不需要考虑线程安全问题。

#include <iostream>

class Singleton {
private:
    static Singleton* instance;

    // 构造函数私有化,防止外部创建实例
    Singleton() {
        std::cout << "Singleton instance created." << std::endl;
    }

public:
    // 获取单例实例
    static Singleton* getInstance() {
        return instance;
    }

    // 删除拷贝构造函数和赋值运算符,防止拷贝
    Singleton(Singleton const&) = delete;
    Singleton& operator=(Singleton const&) = delete;

    // 销毁实例
    static void destroyInstance() {
        delete instance;
        instance = nullptr;
    }

    // 测试方法
    void showMessage() {
        std::cout << "Hello from Singleton!" << std::endl;
    }
};

// 静态成员变量初始化
Singleton* Singleton::instance = new Singleton();

int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();

    s1->showMessage();
    s2->showMessage();

    if (s1 == s2) {
        std::cout << "s1 and s2 are the same instance." << std::endl;
    } else {
        std::cout << "s1 and s2 are different instances." << std::endl;
    }

    Singleton::destroyInstance();
    return 0;
}

多线程安全版单例模式

多线程安全的单例模式通常采用**双重检查锁定(Double-Checked Locking)**技术,确保在多线程环境下只有一个实例被创建。

#include <iostream>
#include <mutex>

class Singleton {
private:
    static Singleton* instance;
    static std::mutex mtx;

    // 构造函数私有化,防止外部创建实例
    Singleton() {
        std::cout << "Singleton instance created." << std::endl;
    }

public:
    // 获取单例实例
    static Singleton* getInstance() {
        // 双重检查锁定,确保线程安全
        if (instance == nullptr) {
            std::lock_guard<std::mutex> lock(mtx);
            if (instance == nullptr) {
                instance = new Singleton();
            }
        }
        return instance;
    }

    // 删除拷贝构造函数和赋值运算符,防止拷贝
    Singleton(Singleton const&) = delete;
    Singleton& operator=(Singleton const&) = delete;

    // 销毁实例
    static void destroyInstance() {
        delete instance;
        instance = nullptr;
    }

    // 测试方法
    void showMessage() {
        std::cout << "Hello from Singleton!" << std::endl;
    }
};

// 静态成员变量初始化
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();

    s1->showMessage();
    s2->showMessage();

    if (s1 == s2) {
        std::cout << "s1 and s2 are the same instance." << std::endl;
    } else {
        std::cout << "s1 and s2 are different instances." << std::endl;
    }

    Singleton::destroyInstance();
    return 0;
}

总结

  • 懒汉式单例模式:在第一次使用时创建实例,适用于实例创建成本较高的情况,但需要考虑线程安全问题。
  • 饿汉式单例模式:在程序启动时创建实例,实现简单,线程安全,但可能会导致资源浪费。
  • 多线程安全版单例模式:通过双重检查锁定技术确保在多线程环境下只有一个实例被创建。

C++ 多例模式示例代码

多例模式(Multiton Pattern) 是单例模式的一种扩展,它允许多个实例,每个实例都有一个唯一的标识符(例如名称)。通过这种方式,可以在需要多个唯一实例的情况下使用多例模式。

在下面的示例中,我们将创建一个多例模式,使用 std::map 来存储实例和它们的名称。我们将创建固定数量的实例,并在需要时通过名称来获取它们。

代码示例

#include <iostream>
#include <map>
#include <string>
#include <memory>

class Multiton {
private:
    // 实例名称
    std::string name;

    // 构造函数私有化,防止外部创建实例
    Multiton(const std::string& name) : name(name) {
        std::cout << "Multiton instance created: " << name << std::endl;
    }

    // 静态成员变量,用于存储多例实例
    static std::map<std::string, std::shared_ptr<Multiton>> instances;

public:
    // 获取多例实例
    static std::shared_ptr<Multiton> getInstance(const std::string& name) {
        auto it = instances.find(name);
        if (it == instances.end()) {
            // 如果实例不存在,创建并存储它
            std::shared_ptr<Multiton> instance = std::make_shared<Multiton>(name);
            instances[name] = instance;
            return instance;
        }
        return it->second;
    }

    // 删除拷贝构造函数和赋值运算符,防止拷贝
    Multiton(Multiton const&) = delete;
    Multiton& operator=(Multiton const&) = delete;

    // 测试方法
    void showMessage() {
        std::cout << "Hello from Multiton " << name << "!" << std::endl;
    }
};

// 静态成员变量初始化
std::map<std::string, std::shared_ptr<Multiton>> Multiton::instances;

int main() {
    // 创建固定数量的实例,每个实例有一个名称
    std::shared_ptr<Multiton> m1 = Multiton::getInstance("Instance1");
    std::shared_ptr<Multiton> m2 = Multiton::getInstance("Instance2");
    std::shared_ptr<Multiton> m3 = Multiton::getInstance("Instance3");

    // 获取已经创建的实例
    std::shared_ptr<Multiton> m4 = Multiton::getInstance("Instance1");
    std::shared_ptr<Multiton> m5 = Multiton::getInstance("Instance2");
    std::shared_ptr<Multiton> m6 = Multiton::getInstance("Instance3");

    // 测试方法调用
    m1->showMessage();
    m2->showMessage();
    m3->showMessage();
    m4->showMessage();
    m5->showMessage();
    m6->showMessage();

    // 检查实例是否相同
    if (m1 == m4 && m2 == m5 && m3 == m6) {
        std::cout << "The instances are the same." << std::endl;
    } else {
        std::cout << "The instances are different." << std::endl;
    }

    return 0;
}

代码说明

  1. 私有构造函数Multiton 类的构造函数是私有的,防止外部直接创建实例。
  2. 静态成员变量 instances:使用 std::map 存储实例名称和对应的实例指针。
  3. getInstance 方法:通过名称获取实例。如果实例不存在,则创建并存储它。
  4. showMessage 方法:用于测试实例是否正常工作。

输出结果

运行上述代码后,输出结果将显示每个实例的创建信息,并验证通过相同名称获取的实例是否相同。

Multiton instance created: Instance1
Multiton instance created: Instance2
Multiton instance created: Instance3
Hello from Multiton Instance1!
Hello from Multiton Instance2!
Hello from Multiton Instance3!
Hello from Multiton Instance1!
Hello from Multiton Instance2!
Hello from Multiton Instance3!
The instances are the same.

总结

多例模式通过 std::map 存储多个实例,每个实例都有一个唯一的标识符(例如名称)。通过这种方式,可以在需要多个唯一实例的情况下使用多例模式,并且可以方便地通过标识符获取实例。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2240633.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

动态规划一>子数组系列

题目&#xff1a; 2.解析&#xff1a; 代码&#xff1a; public int maxSubArray(int[] nums) {int n nums.length;int[] dp new int[n 1];int ret Integer.MIN_VALUE;for(int i 1; i < n; i){dp[i] Math.max(nums[i - 1], dp[i - 1] nums[i - 1]);ret Math.max(…

ctfshow DSBCTF web部分wp

ctfshow 单身杯 web部分wp web 签到好玩的PHP 源码&#xff1a; <?php error_reporting(0); highlight_file(__FILE__);class ctfshow {private $d ;private $s ;private $b ;private $ctf ;public function __destruct() {$this->d (string)$this->d;$this…

【How AI Works】读书笔记2 出发吧! AI纵览 第一部分

目录 1.说明 2.第一部分(P5~P8) 如何控制几乎所有计算机的方式 三个计算机的先驱人物 AI,机器学习和深度学习之间的关系 机器学习的介绍 深度学习的介绍 AI的介绍 模型 3.单词 4.专业术语 1.说明 书全名:How AI Works From Sorcery to Science 作者 Ronald T.Kneus…

MQ集群

目录 MQ集群 集群分类 普通集群 集群结构和特征 集群的部署 获取cookie 准备集群配置 启动集群 镜像模式 镜像模式的特征 镜像模式的配置 exactly模式 仲裁队列 集群特征仲裁队列&#xff1a;仲裁队列是3.8版本以后才有的新功能&#xff0c;用来替代镜像队列&#…

【excel】easy excel如何导出动态列

动态也有多重含义&#xff1a;本文将描述两种动态场景下的解决方案 场景一&#xff1a;例如表头第一列固定为动物&#xff0c;且必定有第二列&#xff0c;第二列的表头可能为猫 也可能为狗&#xff1b;这是列数固定&#xff0c;列名不固定的场景&#xff1b; 场景二&#xff1…

P10901 [蓝桥杯 2024 省 C] 封闭图形个数

铁子们好呀&#xff0c;今天博主给大家更新一道编程题&#xff01;&#xff01;&#xff01; 题目链接如下&#xff1a; P10901 [蓝桥杯 2024 省 C] 封闭图形个数 好&#xff0c;接下来&#xff0c;我将从三个方面讲解这道例题。分别是 题目解析算法原理代码实现 文章目录 1.题…

【深度学习】神经网络优化方法 正则化方法 价格分类案例

神经网络优化方法 正则化方法 价格分类案例 梯度下降法 ​ 梯度下降法是一种寻找损失函数最小的方法,从数学上的角度来看&#xff0c;梯度的方向是函数增长速度最快的方向&#xff0c;那么梯度的反方向就是函数减少最快的方向&#xff0c;所以有&#xff1a; 其中&#xff0c…

UE5 umg学习(四) 将UI控件显示到关卡中

视频资料 7、将UI控件渲染到关卡_哔哩哔哩_bilibili 在前三节里&#xff0c;创建了用户的控件蓝图Widget_BP 目标是运行的时候&#xff0c;开始运行这个蓝图&#xff0c;因此需要在开始事件触发运行 首先&#xff0c;回到主页&#xff0c;点击关卡蓝图 要从事件开始运行时 …

数字图像处理(c++ opencv):图像复原与重建-常见的滤波方法--自适应滤波器

自适应局部降噪滤波器 自适应局部降噪滤波器&#xff08;Adaptive, Local Noise Reduction Filter&#xff09;原理步骤 步骤 &#xff08;1&#xff09;计算噪声图像的方差 &#xff1b; &#xff08;2&#xff09;计算滤波器窗口内像素的均值 和方差 &#xff1b; &…

websocket身份验证

websocket身份验证 前言 上一集我们就完成了websocket初始化的任务&#xff0c;那么我们完成这个内容之后就应该完成一个任务&#xff0c;当客户端与服务端连接成功之后&#xff0c;客户端应该主动发起一个身份认证的消息。 身份认证proto 我们看一眼proto文件的内容。 我…

鸿蒙HarmonyOS 地图不显示解决方案

基于地图的开发准备已完成的情况下&#xff0c;地图还不显式的问题 首先要获取设备uuid 获取设备uuid 安装DevEco Studio的路径下 有集成好的hdc工具 E:\install_tools\DevEco Studio\sdk\default\openharmony\toolchains 这个路径下打开cmd运行 进入“设置 > 关于手机…

Day44 | 动态规划 :状态机DP 买卖股票的最佳时机IV买卖股票的最佳时机III

Day44 | 动态规划 &#xff1a;状态机DP 买卖股票的最佳时机IV&&买卖股票的最佳时机III&&309.买卖股票的最佳时机含冷冻期 动态规划应该如何学习&#xff1f;-CSDN博客 本次题解参考自灵神的做法&#xff0c;大家也多多支持灵神的题解 买卖股票的最佳时机【…

PySpark——Python与大数据

一、Spark 与 PySpark Apache Spark 是用于大规模数据&#xff08; large-scala data &#xff09;处理的统一&#xff08; unified &#xff09;分析引擎。简单来说&#xff0c; Spark 是一款分布式的计算框架&#xff0c;用于调度成百上千的服务器集群&#xff0c;计算 TB 、…

<项目代码>YOLOv8 番茄识别<目标检测>

YOLOv8是一种单阶段&#xff08;one-stage&#xff09;检测算法&#xff0c;它将目标检测问题转化为一个回归问题&#xff0c;能够在一次前向传播过程中同时完成目标的分类和定位任务。相较于两阶段检测算法&#xff08;如Faster R-CNN&#xff09;&#xff0c;YOLOv8具有更高的…

MySQL技巧之跨服务器数据查询:基础篇-动态参数

MySQL技巧之跨服务器数据查询&#xff1a;基础篇-动态参数 上一篇已经描述&#xff1a;借用微软的SQL Server ODBC 即可实现MySQL跨服务器间的数据查询。 而且还介绍了如何获得一个在MS SQL Server 可以连接指定实例的MySQL数据库的连接名: MY_ODBC_MYSQL 以及用同样的方法&a…

三天精通一种算法之螺旋矩阵(设计思路),长度最小子数组(滑动窗口)

这题主要考察思维 我来一一解释这串代码 var generateMatrix function(n) { const matrix Array.from({ length: n }, () > Array(n).fill(0)); let top 0, bottom n - 1; let left 0, right n - 1; var num 1; while (num < n * n) { …

2024-11-13 Unity Addressables1——概述与导入

文章目录 1 概述1.1 介绍1.2 主要作用1.3 Addressables 与 AssetBundle 的区别 2 导入3 配置3.1 方法一3.2 方法二 1 概述 1.1 介绍 ​ Addressables 是可寻址资源管理系统。 ​ Unity 从 2018.2 版本开始&#xff0c;建议用于替代 AssetBundle 的高阶资源管理系统。在 Unit…

python爬虫实战案例——爬取A站视频,m3u8格式视频抓取(内含完整代码!)

1、任务目标 目标网站&#xff1a;A站视频&#xff08;https://www.acfun.cn/v/ac40795151&#xff09; 要求&#xff1a;抓取该网址下的视频&#xff0c;将其存入本地&#xff0c;视频如下&#xff1a; 2、网页分析 进入目标网站&#xff0c;打开开发者模式&#xff0c;我们发…

web实验3:虚拟主机基于不同端口、目录、IP、域名访问不同页面

创建配置文件&#xff1a; 创建那几个目录及文件&#xff0c;并且写内容&#xff1a; 为网卡ens160添加一个 IPv4 地址192.168.234.199/24: 再重新激活一下网卡ens160&#xff1a; 重启服务&#xff1a; 关闭防火墙、改宽松模式&#xff1a; 查看nginx端口监听情况&#xff1a;…

在tiktok开店,商家可以享受到多少显著的优势?

短视频带货正在蓬勃发展&#xff0c;因此&#xff0c;许多人开始利用自媒体平台进行商品销售。越来越多的商家选择在TikTok上开设店铺。那么&#xff0c;在TikTok上开店&#xff0c;商家可以享受到哪些显著的优势呢&#xff1f; 1. 庞大的用户基础 TikTok拥有海量的用户群体&…