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

news/2024/12/22 14:50:20/

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.ppmy.cn/news/1230867.html

相关文章

在 Windows 中关闭 Nginx 所有进程

在 Windows 中关闭 Nginx 所有进程并强制重启的命令如下&#xff1a; 打开命令提示符&#xff08;CMD&#xff09;。 输入以下命令来查找 Nginx 进程的 PID&#xff1a; tasklist /fi "imagename eq nginx.exe"此命令将列出所有名为 nginx.exe 的进程以及它们的 PID…

Visio免费版!Visio国产平替软件,终于被我找到啦!

作为一个职场人士&#xff0c;我经常需要绘制各种流程图和图表&#xff0c;而Visio一直是我使用的首选工具。但是&#xff0c;随着公司的发展和工作的需要&#xff0c;我逐渐发现了Visio的优点和不足。 首先&#xff0c;让我们来看看Visio的优点。Visio是一个专业的流程图和图…

JVS低代码表单设计:数据联动详解(多级数据级、数据回显等)

在这信息化时代&#xff0c;表单作为数据的收集和展示工具&#xff0c;已经渗透到不同的角落。JVS低代码对表单的设计和操作进行了不断的优化和创新。其中&#xff0c;联动回显作为一项重要的功能&#xff0c;无论是多级数据级联控制、组件的联动控制&#xff0c;还是多表的数据…

数据中心走向绿色低碳,液冷存储舍我其谁

引言&#xff1a;没有最冷&#xff0c;只有更冷&#xff0c;绿色低碳早已成为行业关键词。 【全球存储观察 &#xff5c; 科技热点关注】 每一次存储行业的创新&#xff0c;其根源离不开行业端的用户需求驱动。 近些年从数据中心建设的整体发展情况来看&#xff0c;从风冷到…

基于单片机GPS轨迹定位和里程统计系统

**单片机设计介绍&#xff0c; 基于单片机GPS轨迹定位和里程统计系统 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 一个基于单片机、GPS和里程计的轨迹定位和里程统计系统可以被设计成能够在移动的交通工具中精确定位车辆的位置…

裸片-PCBA

裸片 PCBA&#xff0c; 薄膜&#xff0c; 邦定-COB&#xff08;chip on board&#xff09;技术是指将裸芯片直接贴在PCB 板上&#xff0c;然后用铝线或金线进行电子连接的技术

制作Go程序的Docker容器(以及容器和主机的网络问题)

今天突然遇到需要将 Go 程序制作成 Docker 的需求&#xff0c;所以进行了一些研究。方法很简单&#xff0c;但是官方文档和教程有些需要注意的地方&#xff0c;所以写本文进行记录。 源程序 首先介绍一下示例程序&#xff0c;示例程序是一个 HTTP 服务器&#xff0c;会显示si…