C++—单例设计模式

单例设计模式

C++中的单例设计模式是一种常用的软件设计模式,其核心目的是确保一个类仅有一个实例,并提供一个全局访问点来获取这个实例。以下是对C++单例设计模式的详细解释:

一、单例设计模式的定义

单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。

二、单例设计模式的实现方式

在C++中,单例模式的实现方式多种多样,但基本思想都是将构造函数私有化,并通过一个静态方法提供类的唯一实例。以下是几种常见的实现方式:

  1. 懒汉式(线程不安全)
    • 延迟加载实例,即在需要时才创建实例。
    • 但在多线程环境下存在线程安全问题。
  2. 懒汉式(线程安全)
    • 通过加锁(如使用std::mutex)来保证在多线程环境下的线程安全。
    • 但每次访问实例时都需要加锁,可能会影响性能。
  3. 饿汉式
    • 在程序启动时立即创建实例,因此本身是线程安全的。
    • 但无论是否使用实例,都会立即创建,可能会浪费资源。
  4. 双重检查锁定(Double-Check Locking)
    • 一种优化懒汉式线程安全实现的方法。
    • 通过两次检查实例是否存在来减少加锁的次数,从而提高性能。
  5. 静态局部变量(C++11推荐)
    • 利用C++11中静态局部变量的线程安全特性来实现单例。
    • 这种方法既实现了延迟加载,又保证了线程安全。
  6. 使用智能指针
    • 将实例封装在智能指针中,如std::unique_ptrstd::shared_ptr,以自动管理内存。
  7. 使用std::call_once
    • C++11引入的std::call_once函数可以保证某个函数在程序执行期间只被调用一次。
    • 可以利用这个特性来实现线程安全的单例初始化。

三、单例设计模式的优缺点

优点

  1. 控制资源访问:确保对共享资源的独占访问。
  2. 简化全局访问:提供一个全局访问点,方便使用。
  3. 实现数据共享:可以在多个对象之间共享数据。

缺点

  1. 单例对象生命周期管理困难:单例对象通常在整个应用程序的生命周期内都存在,这可能导致资源无法及时释放。
  2. 扩展性差:如果需要创建多个实例,则需要对代码进行较大修改。
  3. 隐藏类的依赖关系:使用单例模式的类通常与其他类紧密耦合,这可能导致代码难以理解和维护。

四、单例设计模式的应用场景

单例设计模式适用于以下场景:

  1. 全局配置管理:如读取配置文件并管理配置信息。
  2. 数据库连接池:管理数据库连接,确保全局只有一个连接池。
  3. 日志记录器:确保全局只有一个日志记录器实例,用于记录应用程序的日志信息。
  4. 状态管理:在需要全局状态管理的场景中,如游戏开发中的游戏状态管理等。

总之,C++中的单例设计模式是一种非常有用的设计模式,但在使用时需要注意其优缺点和适用场景,以避免过度使用或误用导致的问题。

五、案例测试

1.懒汉式(线程安全)

#include <iostream>  
#include <mutex>  class Singleton {  
private:  static Singleton* instance;  static std::mutex mtx;  Singleton() {} // 私有构造函数,防止外部直接创建实例  // 禁止拷贝构造函数和赋值运算符  Singleton(const Singleton&) = delete;  Singleton& operator=(const Singleton&) = delete;  public:  static Singleton* getInstance() {  std::lock_guard<std::mutex> lock(mtx); // 使用锁保护  if (!instance) {  instance = new Singleton();  }  return instance;  }  void doSomething() {  std::cout << "Doing something..." << std::endl;  }  // 静态成员需要在类外初始化  static Singleton* instance_init() {  return nullptr;  }  static std::mutex mtx_init() {  return std::mutex();  }  
};  // 初始化静态成员  
Singleton* Singleton::instance = Singleton::instance_init();  
std::mutex Singleton::mtx = Singleton::mtx_init();  int main() {  Singleton* s1 = Singleton::getInstance();  Singleton* s2 = Singleton::getInstance();  if (s1 == s2) {  std::cout << "s1 and s2 are the same instance." << std::endl;  }  s1->doSomething();  s2->doSomething();  return 0;  
}

注意:虽然上面的代码使用了std::mutex来保证线程安全,但在实际使用中,如果单例的创建和销毁不是性能瓶颈,并且你确信单例的创建是线程安全的(例如,在程序启动时由主线程创建),那么可能不需要额外的线程安全措施。

2.静态局部变量(C++11推荐)

#include <iostream>  class Singleton {  
private:  Singleton() {} // 私有构造函数,防止外部直接创建实例  // 禁止拷贝构造函数和赋值运算符  Singleton(const Singleton&) = delete;  Singleton& operator=(const Singleton&) = delete;  static Singleton& getInstanceHelper() {  static Singleton instance; // 局部静态变量,线程安全  return instance;  }  public:  static Singleton& getInstance() {  return getInstanceHelper();  }  void doSomething() {  std::cout << "Doing something..." << std::endl;  }  
};  int main() {  Singleton& s1 = Singleton::getInstance();  Singleton& s2 = Singleton::getInstance();  // s1 和 s2 实际上是同一个实例的引用  std::cout << "&s1: " << &s1 << std::endl;  std::cout << "&s2: " << &s2 << std::endl;  s1.doSomething();  s2.doSomething();  return 0;  
}

在这个例子中,我使用了C++11的局部静态变量特性来确保单例的线程安全性和懒加载。这种方法既简单又高效,是推荐的实现方式之一。注意,由于我们返回的是引用而不是指针,因此不需要担心内存管理问题。

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

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

相关文章

精密制造的革新:光谱共焦传感器与工业视觉相机的融合

在现代精密制造领域&#xff0c;对微小尺寸、高精度产品的检测需求日益迫切。光谱共焦传感器凭借其非接触、高精度测量特性脱颖而出&#xff0c;而工业视觉相机则以其高分辨率、实时成像能力著称。两者的融合&#xff0c;不仅解决了传统检测方式在微米级别测量上的局限&#xf…

【C++】入门基础知识-1

&#x1f36c;个人主页&#xff1a;Yanni.— &#x1f308;数据结构&#xff1a;Data Structure.​​​​​​ &#x1f382;C语言笔记&#xff1a;C Language Notes &#x1f3c0;OJ题分享&#xff1a; Topic Sharing 目录 前言&#xff1a; C关键字 命名空间 命名空间介…

使用 Llama-index 实现的 Agentic RAG-Router Query Engine

前言 你是否也厌倦了我在博文中经常提到的老式 RAG(Retrieval Augmented Generation | 检索增强生成) 系统&#xff1f;反正我是对此感到厌倦了。但我们可以做一些有趣的事情&#xff0c;让它更上一层楼。接下来就跟我一起将 agents 概念引入传统的 RAG 工作流&#xff0c;重新…

凌晨1点开播!Meta Connect 2024开发者大会,聚焦Llama新场景和AR眼镜

作者&#xff1a;十九 编辑&#xff1a;李宝珠 北京时间 9 月 26 日凌晨 1 点&#xff0c;Meta Connect 2024 开发者大会即将举行&#xff0c;马克扎克伯格将聚焦 AI 和元宇宙&#xff0c;向大家分享 Llama 模型的更多潜在应用&#xff0c;并介绍 Meta 最新产品 AR 眼镜和 Meta…

OceanBase云数据库战略实施两年,受零售、支付、制造行业青睐

2022年OceanBase推出云数据库产品OB Cloud,正式启动云数据库战略。两年来OB Cloud发展情况如何&#xff0c;9月26日&#xff0c;OceanBase公有云事业部总经理尹博学向记者作了介绍。 尹博学表示&#xff0c;OB Cloud推出两年以来&#xff0c;已服务超过700家客户&#xff0c;客…

Pydantic 是一个强大的 Python 库

Pydantic 是一个强大的 Python 库&#xff0c;专门用于数据验证和设置管理。以下是对 Pydantic 的详细介绍&#xff1a; 一、主要功能和特点 数据验证&#xff1a; Pydantic 通过 Python 类型注解来定义数据模型&#xff0c;并自动验证输入数据是否符合预定义的类型和结构。提…

智算中心动环监控:构建高效、安全的数字基础设施@卓振思众

在当今快速发展的数字经济时代&#xff0c;智算中心作为人工智能和大数据技术的核心支撑设施&#xff0c;正日益成为各行业实现智能化转型的重要基石。为了确保这些高性能计算环境的安全与稳定&#xff0c;卓振思众动环监控应运而生&#xff0c;成为智算中心管理的重要组成部分…

计算机知识科普问答--19(91-95)

文章目录 91、为什么会产生死锁?什么是死锁?死锁产生的四个必要条件信号量机制中的死锁原因示例:可能导致死锁的信号量使用如何避免死锁在之前的信号量问题中如何避免死锁【2011年408真题】银行系统示例缓冲区问题示例具体示例:避免死锁的代码设计顾客进程 \( P_{\text{cus…

理解Java引用数据类型(数组、String)传参机制的一个例子

目录 理解Java引用数据类型&#xff08;数组、String&#xff09;传参机制的一个例子理解样例代码输出 参考资料 理解Java引用数据类型&#xff08;数组、String&#xff09;传参机制的一个例子 理解 引用数据类型传递的是地址。用引用类型A给引用类型B赋值&#xff0c;相当于…

[半导体检测-5]:软件离线许可(License)的基本原理

目录 前言&#xff1a; 一、软件离线许可的基本概念 二、实现原理 1. 数字签名技术 2. 授权信息包含内容 3. 时间戳验证 三、实际应用与操作建议 1. 离线许可的分配与安装 2. 常见问题与解决方法 四、总结 前言&#xff1a; 在软件行业&#xff0c;离线许可&#xf…

【自动驾驶】ros如何隔绝局域网内其他电脑播包

1.问题 可能碰到自己播包的时候&#xff0c;别人播包的传到我们电脑上&#xff0c;导致无法分析问题&#xff0c;或者出现一些奇怪的现象。 2.解决 export ROS_LOCALHOST_ONLY1 在终端加上这句话&#xff0c;或者在~/.bashrc中添加&#xff0c;通过source ~/.bashrc使其生…

Java 入门指南:获取对象的内存地址

文章目录 hashCode()应用重写 hashCode() 方法示例 Symstem . indentityHashCode()应用 注意事项 在 Java 开发中&#xff0c;了解对象的内存管理是十分重要的&#xff0c;尽管 Java 的设计初衷是让开发者更专注于业务逻辑而非底层资源管理。但在某些情况下&#xff0c;了解对象…

Linux(含麒麟操作系统)如何实现多显示器屏幕采集录制

技术背景 在操作系统领域&#xff0c;很多核心技术掌握在国外企业手中。如果过度依赖国外技术&#xff0c;在国际形势变化、贸易摩擦等情况下&#xff0c;可能面临技术封锁和断供风险。开发国产操作系统可以降低这种风险&#xff0c;确保国家关键信息基础设施的稳定运行。在一…

【C++位图】构建灵活的空间效率工具

目录 位图位图的基本概念如何用位图表示数据位图的基本操作setresettest 封装位图的设计 总结 在计算机科学中&#xff0c;位图&#xff08;Bitmap&#xff09;是一种高效的空间管理数据结构&#xff0c;广泛应用于各种场景&#xff0c;如集合操作、图像处理和资源管理。与传统…

一文读懂 Pencils Protocol 近期不可错过的市场活动

Pencils Protocol 是 Scroll 上综合性的 DeFi 协议&#xff0c;自 9 月 18 日开始其陆续在 Tokensoft、Bounce、Coresky 等平台开启 DAPP 通证的销售&#xff0c;并分别在短期内完成售罄。吸引了来自韩国、CIS、土耳其等 70 多个国家的 5 万多名认证用户&#xff0c;反响热烈&a…

Jmeter关联,断言,参数化

一、关联 常用的关联有三种 1.边界提取器 2.JSON提取器 3.正则表达式提取器 接下来就详细讲述一下这三种的用法 这里提供两个接口方便练习 登录接口 接口名称&#xff1a;登录 接口提交方式&#xff1a;POST 接口的url地址&#xff1a;https://admin-api.macrozheng.com/a…

Python中的文件编码:揭开字符世界的神秘面纱

引言 在计算机系统中&#xff0c;数据是以二进制形式存储的。而我们日常见到的文字、符号等信息&#xff0c;则需要通过特定的方式转化为二进制数据&#xff0c;这就是编码的过程。不同的编码方式决定了如何将字符映射成字节序列。选择合适的编码方案不仅能够保证信息传输的准…

C#常用数据结构栈的介绍

定义 在C#中&#xff0c;Stack<T> 是一个后进先出&#xff08;LIFO&#xff0c;Last-In-First-Out&#xff09;集合类&#xff0c;位于System.Collections.Generic 命名空间中。Stack<T> 允许你将元素压入栈顶&#xff0c;并从栈顶弹出元素。 不难看出&#xff0c;…

Oracle 单机和集群环境部署教程

目录 一、Oracle 单机环境部署1. 环境准备2. 安装 Oracle Database2.1 下载 Oracle Database2.2 创建 Oracle 用户和组2.3 配置内核参数和系统限制2.4 解压和安装2.5 配置监听程序2.6 创建数据库 3. 单机部署注意事项 二、Oracle 集群环境部署 (Oracle RAC)1. 环境准备2. 安装 …

SpringBoot-Starter2.7.3自动装配Redisson升级版本运行时的问题

序言 在github上搜索redisson官方源码中的issue其他伙伴们提交的记录。 https://github.com/spring-projects/spring-data-redis/tree/main/src/main/java/org/springframework/data/redis/connection/zset 基础工程的pom文件中的依赖结构 springboot version <depende…