单例模式如何实现?

单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例。在 C++ 中,可以通过将构造函数设为私有,并提供一个静态方法来获取或创建类的实例来实现单例模式。

下面是一个简单的 C++ 单例模式的实现示例:

#include <iostream>  
#include <mutex> // 用于线程安全(可选)  class Singleton {  
private:  // 私有的静态指针,指向单例对象  static Singleton* instance;  // 私有的构造函数,防止外部创建实例  Singleton() {}  // 私有的拷贝构造函数和赋值运算符,防止拷贝  Singleton(const Singleton&) = delete;  Singleton& operator=(const Singleton&) = delete;  // 静态互斥锁(可选,用于多线程环境)  static std::mutex mtx;  public:  // 静态方法,用于获取单例对象  static Singleton* getInstance() {  // 使用互斥锁保证线程安全(可选)  std::lock_guard<std::mutex> lock(mtx);  // 如果实例不存在,则创建它  if (instance == nullptr) {  instance = new Singleton();  }  return instance;  }  // 其他公共成员函数...  void doSomething() {  std::cout << "Singleton is doing something." << std::endl;  }  // 静态析构函数(可选),用于在程序结束时清理单例对象  // 注意:C++11 开始支持静态成员和局部对象的析构函数,但通常不推荐这样做  // 因为在程序结束时,所有资源都应该被自动清理  static void destroyInstance() {  if (instance != nullptr) {  delete instance;  instance = nullptr;  }  }  // 析构函数设为保护或私有的(可选),防止外部删除实例  
protected:  ~Singleton() {  // 单例对象销毁时的清理工作(如果有的话)  }  
};  // 初始化静态成员(在类外部)  
Singleton* Singleton::instance = nullptr;  
std::mutex Singleton::mtx;  // 使用示例  
int main() {  Singleton* s1 = Singleton::getInstance();  Singleton* s2 = Singleton::getInstance();  // s1 和 s2 指向同一个对象  if (s1 == s2) {  std::cout << "s1 and s2 are the same instance." << std::endl;  }  s1->doSomething(); // 调用单例对象的成员函数  // 在程序结束时,可以调用 destroyInstance 来清理单例对象(通常不推荐)  // Singleton::destroyInstance();  return 0;  
}

注意

  1. 在多线程环境中,上述示例中的 getInstance 方法不是线程安全的。为了确保线程安全,可以使用互斥锁(如 std::mutex)来保护创建实例的代码块。
  2. 在 C++11 及更高版本中,可以使用局部静态变量的方式来实现线程安全的单例模式,因为局部静态变量的初始化是线程安全的。
  3. 析构函数通常不需要设为保护或私有的,因为单例对象应该在程序结束时自动被销毁。但在某些情况下,为了防止外部代码误删单例对象,可以将析构函数设为保护或私有的。如果这样做,需要提供一个静态方法来清理单例对象(如 destroyInstance),但这通常不推荐,因为它可能导致资源泄漏或其他问题。

在 C++11 及以后的版本中,我们可以使用更简洁和线程安全的方式来实现单例模式。以下是一个基于 C++11 的线程安全单例模式的实现示例:

#include <iostream>  
#include <memory>  
#include <mutex>  class Singleton {  
private:  // 静态成员指针,指向单例对象  static std::unique_ptr<Singleton> instance;  // 私有的构造函数  Singleton() {}  // 禁止拷贝和移动  Singleton(const Singleton&) = delete;  Singleton& operator=(const Singleton&) = delete;  Singleton(Singleton&&) = delete;  Singleton& operator=(Singleton&&) = delete;  public:  // 静态方法,用于获取单例对象  static Singleton& getInstance() {  // 使用 std::call_once 来保证线程安全  static std::once_flag flag;  std::call_once(flag, [] {  instance.reset(new Singleton());  });  return *instance;  }  // 其他成员函数...  void doSomething() {  std::cout << "Singleton is doing something." << std::endl;  }  // 不需要显式销毁单例,unique_ptr 会在程序结束时自动处理  
};  // 初始化静态成员(在类外部)  
std::unique_ptr<Singleton> Singleton::instance;  // 使用示例  
int main() {  Singleton& s1 = Singleton::getInstance();  Singleton& s2 = Singleton::getInstance();  // s1 和 s2 引用同一个对象  if (&s1 == &s2) {  std::cout << "s1 and s2 are the same instance." << std::endl;  }  s1.doSomething(); // 调用单例对象的成员函数  return 0;  
}

在这个实现中,我们使用了 std::unique_ptr 来管理单例对象的生命周期,确保在程序结束时能够自动释放内存。同时,我们使用了 std::call_once 和 std::once_flag 来保证 getInstance 方法的线程安全性。由于 std::call_once 保证了初始化函数只会被执行一次,因此即使多个线程同时调用 getInstance 方法,也只会有一个线程创建单例对象。

此外,我们还使用了引用 Singleton& 而不是指针 Singleton* 来返回单例对象,这样可以简化代码并减少出错的可能性。由于 std::unique_ptr 已经管理了对象的生命周期,我们不需要担心内存泄漏或其他与内存管理相关的问题。

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

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

相关文章

Linux日常管理和服务器配置(二)

一、在系统中配置FTP服务器&#xff1a; 准备工作&#xff1a; a.下载ftp命令 sudo apt install vsftpd 可以先用命令更新一下库 sudo apt-get update 接着输入 systemctl status vsftpd 检查ftp运行状态 然后进入vsftpd.conf文件中修改write为 vim /etc/vsftpdf.conf …

深入理解指针(1)

在之前我们学习了许多c语言的基础知识&#xff0c;让我们初步了解了c语言&#xff0c;接下来将来到c语言中一个重点的知识章节--指针&#xff0c;学习完指针后将会让我们对c语言有更深入的理解&#xff0c;接下来就开始指针的讲解 1.内存与地址 1.指针 在了解内存与地址前&am…

vue开发网站—①调用$notify弹窗、②$notify弹窗层级问题、③js判断两个数组是否相同等。

一、vue中如何使用vant的 $notify&#xff08;展示通知&#xff09; 在Vue中使用Vant组件库的$notify方法来展示通知&#xff0c;首先确保正确安装了Vant并在项目中引入了Notify组件。 1.安装vant npm install vant --save# 或者使用yarn yarn add vant2.引入&#xff1a;在ma…

词令蚂蚁新村今日答案:微信小程序怎么查看蚂蚁新村今天问题的正确答案?

微信小程序怎么查看蚂蚁新村今天问题的正确答案&#xff1f; 1、打开微信&#xff0c;点击搜索框&#xff1b; 2、打开搜索页面&#xff0c;选择小程序搜索&#xff1b; 3、在搜索框&#xff0c;输入词令搜索点击进入词令微信小程序&#xff1b; 4、打开词令微信小程序关键词口…

Python专题:九、元组

append&#xff08;&#xff09;函数添加列表元素 remove&#xff08;&#xff09;函数移除列表元素 数据存储知识 变量保存的就是数据在内存中的地址 id()函数查看变量存储地址 动态分配 内存地址是动态分配的&#xff0c;每次的数值不一致 copy&#xff08;&#xff09;函…

学习Vue3中reactive

学习Vue3中reactive 一、前言1、响应式对象2、对象属性的访问3、嵌套响应式对象4、避免直接修改响应式对象5、ref vs reactive 一、前言 在 Vue 3 中&#xff0c;reactive 是一个用于创建响应式对象的函数。响应式对象是 Vue 3 中数据驱动视图的核心&#xff0c;它们的属性的变…

redis的双写一致性

双写一致性问题 1.先删除缓存或者先修改数据库都可能出现脏数据。 2.删除两次缓存&#xff0c;可以在一定程度上降低脏数据的出现。 3.延时是因为数据库一般采用主从分离&#xff0c;读写分离。延迟一会是让主节点把数据同步到从节点。 1.读写锁保证数据的强一致性 因为一般放…

代码随想录训练营Day26:贪心算法:04

1.860柠檬水找零 贪心策略&#xff1a;先找大钱&#xff0c;再找小钱&#xff0c;20的不参与找钱 思路&#xff1a;用five,ten存放5元和10元的个数&#xff0c;初始化都是0&#xff0c;如果给的钱是5元&#xff0c;直接five,如果给的是10元&#xff0c;只能找5&#xff0c;判…

音视频入门基础:像素格式专题(2)——不通过第三方库将RGB24格式视频转换为BMP格式图片

音视频入门基础&#xff1a;像素格式专题系列文章&#xff1a; 音视频入门基础&#xff1a;像素格式专题&#xff08;1&#xff09;——RGB简介 音视频入门基础&#xff1a;像素格式专题&#xff08;2&#xff09;——不通过第三方库将RGB24格式视频转换为BMP格式图片 一、引…

AI领域最伟大的论文检索网站

&#x1f4d1; 苏剑林&#xff08;Jianlin Su&#xff09;开发的“Cool Papers”网站旨在通过沉浸式体验提升科研工作者浏览论文的效率和乐趣。这个平台的核心优势在于利用Kimi的智能回答功能&#xff0c;帮助用户快速了解论文的常见问题&#xff08;FAQ&#xff09;&#xff0…

基于Qt的Model-View显示树形数据

目标 用qt的模型-视图框架实现树型层次节点的显示&#xff0c;从QAbstractItemModel派生自己的模型类MyTreeItemModel&#xff0c;用boost::property_tree::ptree操作树型数据结构&#xff0c;为了演示&#xff0c;此处只实现了个只读的模型 MyTreeItemModel的定义 #pragma o…

数据结构(一)绪论

2024年5月11日 一稿 数据元素+数据项 逻辑结构 集合 线性结构 树形结构 </

SGP.02-v4.2-001

2.4 OTA Communication on ES5 (SM-SR-eUICC) 2.4.3 SMS 在eUICC&#xff08;嵌入式通用集成电路卡&#xff09;远程配置和管理系统中&#xff0c;OTA&#xff08;空中传输&#xff09;通信由SM-SR&#xff08;订阅管理-服务器&#xff09;专门处理。SM-SR可以使用短信&…

chromium添加一个书签项,并自动显示图标

添加一个书签很简单&#xff1a; BookmarkModel* model BookmarkModelFactory::GetForBrowserContext(browser->profile()); const bookmarks::BookmarkNode* node bookmarks::AddIfNotBookmarked(model, url, title); 两句话即可。麻烦的是怎么设置完书签以后还要显示…

php开发的知识付费系统,教育机构如何实现快速招生呢?

如今教育培训市场的竞争越来越激烈&#xff0c;很多机构管理者会抱怨自己机构所在地竞争力太强&#xff0c;生源太少。想要突破机构的招生瓶颈&#xff0c;机构管理者应该如何快速招生呢? 一、无硝烟的战争—地推 校长们&#xff0c;你们知道吗? 如今互联网技术一流的阿里巴巴…

洛谷 P3809:后缀排序 ← 后缀数组

【题目来源】https://www.luogu.com.cn/problem/P3809【题目描述】 读入一个长度为 n 的由大小写英文字母或数字组成的字符串&#xff0c;请把这个字符串的所有非空后缀按字典序&#xff08;用 ASCII 数值比较&#xff09;从小到大排序&#xff0c;然后按顺序输出后缀的第一个字…

【驱动】SPI

1、简介 SPI(Serial Peripheral interface)串行外设接口。 特点: 高速:最大几十M,比如,AD9361的SPI总线速度可以达到40MHz以上全双工:主机在MOSI线上发送一位数据,从机读取它,而从机在MISO线上发送一位数据,主机读取它一主多从:主机产生时钟信号,通过片选引脚选择…

详解Python测试框架Pytest的参数化

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 上篇博文介绍过&#xff0c;Pytest是目前比较成熟功能齐全的测试框架&#xff0c;使用率肯定也不…

Coursera吴恩达深度学习专项课程01: Neural Networks and Deep Learning 学习笔记 Week 03

Neural Networks and Deep Learning Course Certificate 本文是学习 https://www.coursera.org/learn/neural-networks-deep-learning 这门课的笔记 Course Intro 文章目录 Neural Networks and Deep LearningWeek 03: Shallow Neural NetworksLearning Objectives Neural Ne…

13.Netty组件EventLoopGroup和EventLoop介绍

EventLoop 是一个单线程的执行器&#xff08;同时维护了一个Selector&#xff09;&#xff0c;里面有run方法处理Channel上源源不断的io事件。 1.继承java.util.concurrent.ScheduledExecutorService因此包含了线程池中所有的方法。 2.继承netty自己的OrderedEventExecutor …