当前位置: 首页 > news >正文

c++模式之单例模式详解

c++模式之单例模式详解

  • 1.概念
  • 2.懒汉模式示例(缺点)
  • 3.懒汉模式线程安全
  • 4.饿汉式创建单例
  • 5.饿汉模式线程示例

1.概念

单例模式是指在整个系统生命周期内,保证一个类只能产生一个实例,确保该类的唯一性.
使用单例两个原因:
1.节省资源。一个类只有一个实例,不存在多份实例,节省资源。
2.方便控制。在一些操作公共资源的场景时,避免了多个对象引起的复杂操作
单例类的特点

  • 构造函数和析构函数为私有类型,目的是禁止外部构造和析构。
  • 拷贝构造函数和赋值构造函数是私有类型,目的是禁止外部拷贝和赋值,确保实例的唯一性。
  • 类中有一个获取实例的静态方法,可以全局访问。

2.懒汉模式示例(缺点)

getInstance函数使用了懒汉式单例模式的实现方式。它首先检查静态成员变量instance是否为空,如果为空则创建一个新的实例,否则直接返回已有的实例。这种实现方式在单线程环境下是有效的,但在多线程环境下可能会导致线程安全问题。
在多线程环境下,多个线程可能会同时检查到instance为空,然后同时创建多个实例,违背了单例模式的初衷。为了解决这个问题,我们需要在创建实例时添加同步机制,以确保只有一个线程能够创建实例。

#include <iostream>
#include <mutex>
#include <ctime>
#include <vector>
using namespace std;void sleep(int time) { clock_t head = clock(); while (clock() - head <= time) {} }class Singleton {
private:static Singleton* instance; // 静态成员变量,用于保存单例实例Singleton() {} // 私有构造函数,防止外部实例化public:static Singleton* getInstance() {if (instance == nullptr) {instance = new Singleton();}return instance;}void someFunction() {// 单例的其他成员函数cout << "HELLO WORLD" << endl;}
};Singleton* Singleton::instance = nullptr; // 初始化静态成员变量int main() {Singleton* obj1 = Singleton::getInstance();obj1->someFunction();Singleton* obj2 = Singleton::getInstance();obj2->someFunction();// obj1和obj2是同一个实例return 0;
}

3.懒汉模式线程安全

添加了一个静态成员变量mutex作为互斥锁,用于线程同步。在getInstance函数中,我们首先进行一次非线程安全的检查,如果instance为空,才会获取互斥锁并再次检查instance是否为空。这样可以确保只有一个线程能够创建实例。
使用了std::lock_guard来自动管理锁的加锁和解锁,以避免手动处理锁的释放。这样可以确保在任何情况下,无论是正常返回还是发生异常,都会自动释放锁。
这个改进后的示例提供了一种线程安全的懒汉式单例模式实现方式,可以在多线程环境下正常工作

#include <iostream>
#include <mutex>
using namespace std;class Singleton {
private:static Singleton* instance; // 静态成员变量,用于保存单例实例static std::mutex mutex; // 互斥锁,用于线程同步Singleton() {} // 私有构造函数,防止外部实例化public:static Singleton* getInstance() {if (instance == nullptr) {lock_guard<std::mutex> lock(mutex); // 加锁if (instance == nullptr) {instance = new Singleton();}}return instance;}void someFunction() {// 单例的其他成员函数cout << "mutex hello world" << endl;}
};Singleton* Singleton::instance = nullptr; // 初始化静态成员变量
std::mutex Singleton::mutex; // 初始化互斥锁int main() {Singleton* obj1 = Singleton::getInstance();obj1->someFunction();Singleton* obj2 = Singleton::getInstance();obj2->someFunction();// obj1和obj2是同一个实例return 0;
}

4.饿汉式创建单例

它是一种在程序启动时就创建实例的单例模式。下面是一个简单的示例来说明如何实现C++的饿汉式单例模式。

Singleton类使用饿汉式的方式创建实例。在静态成员变量instance的定义处,我们直接使用new操作符创建了一个Singleton的实例,并将其赋值给instance。这样,在程序启动时,实例就会被创建并初始化。
在getInstance函数中,我们直接返回已经创建好的实例,而无需再进行实例化。
在main函数中,我们通过调用Singleton::getInstance()来获取单例实例,并调用其成员函数。由于使用了饿汉式创建实例,obj1和obj2实际上是同一个实例。
饿汉式在程序启动时就创建了实例,因此会占用一定的内存空间。此外,如果实例的创建过程较为复杂或耗时,可能会影响程序的启动速度。因此,在选择单例模式的实现方式时,需要根据具体的需求和场景来决定使用懒汉式还是饿汉式。

#include <iostream>
using namespace std;class Singleton {
private:static Singleton* instance; // 静态成员变量,用于保存单例实例Singleton() {} // 私有构造函数,防止外部实例化public:static Singleton* getInstance() {return instance;}void someFunction() {cout << "Hungry Han style instance" << endl;}
};Singleton* Singleton::instance = new Singleton(); // 在静态成员变量初始化时创建实例int main() {Singleton* obj1 = Singleton::getInstance();obj1->someFunction();Singleton* obj2 = Singleton::getInstance();obj2->someFunction();// obj1和obj2是同一个实例return 0;
}

5.饿汉模式线程示例

#include <iostream>
#include <thread>
using namespace std;class ThreadSingleton {
private:static ThreadSingleton* instance; // 静态成员变量,用于保存单例实例ThreadSingleton() {} // 私有构造函数,防止外部实例化public:static ThreadSingleton* getInstance() {return instance;}void calculateSquareArea(double side) {double area = side * side;std::cout << "The area of the square is: " << area << std::endl;}
};ThreadSingleton* ThreadSingleton::instance = new ThreadSingleton(); // 在静态成员变量初始化时创建实例int main() {std::thread t1([&]() {ThreadSingleton* obj1 = ThreadSingleton::getInstance();obj1->calculateSquareArea(5);});std::thread t2([&]() {ThreadSingleton* obj2 = ThreadSingleton::getInstance();obj2->calculateSquareArea(8);});t1.join();t2.join();return 0;
}
http://www.lryc.cn/news/238147.html

相关文章:

  • 【gpts】学算法题[缺失的第一个正数](https://leetcode.cn/problems/first-missing-positive/)
  • 车牌识别 支持12种中文车牌类型 车牌数据集下载
  • Servlet---上传文件
  • 量子计算+物流!“最后一英里”配送难题Unisys成功实时决策
  • 2023年【四川省安全员A证】复审考试及四川省安全员A证考试试题
  • C++刷题 -- 二分查找
  • PHPmail 发送邮件错误 550 的原因是什么?
  • 数字化转型导师坚鹏:数字化时代银行网点厅堂营销5大难点分析
  • www.testfire.nets渗透测试报告
  • 多模态大一统:通向全模态学习和通用人工智能的未来之路
  • 实用篇-ES-DSL查询文档
  • Nacos配置管理
  • 【前端学java】Java中的异常处理(15)完结
  • 深入理解MySQL存储引擎、InnoDB与MyISAM的比较以及事务处理机制
  • webpack 中,filename 和 chunkFilename 的区别
  • gitlab 实战
  • openGauss学习笔记-128 openGauss 数据库管理-设置透明数据加密(TDE)
  • Redis从入门到精通(三)-高阶篇
  • 线性表--队列-1
  • 【开题报告】基于uni-app的汽车租赁app的设计与实现
  • Java实现围棋算法
  • python -opencv 边缘检测
  • Hadoop-- hdfs
  • 《论文阅读》CAB:认知、情感和行为的共情对话生成 DASFAA 2023
  • 审计dvwa高难度命令执行漏洞的代码,编写实例说明如下函数的用法
  • 国科大数据挖掘期末复习——聚类分析
  • 【经验之谈·高频PCB电路设计常见的66个问题】
  • 科大讯飞 vue.js 语音听写流式实现 全网首发
  • 局域网文件共享神器:Landrop
  • 如何使用Docker部署Apache+Superset数据平台并远程访问?