单例模式【C++设计模式】

server/2025/2/24 10:44:42/

文章目录

单例模式

饿汉模式

  1. 将构造函数设置为私有,并将拷贝构造函数和赋值运算符重载函数设置为私有或删除,防止外部创建或拷贝对象。
  2. 提供一个指向单例对象的static指针,并在程序入口之前完成单例对象的初始化。
  3. 提供一个全局访问点获取单例对象
class Singleton
{
public://3、提供一个全局访问点获取单例对象static Singleton* GetInstance(){return _inst;}
private://1、将构造函数设置为私有,并防拷贝Singleton(){}Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;//2、提供一个指向单例对象的static指针static Singleton* _inst;
};//在程序入口之前完成单例对象的初始化
Singleton* Singleton::_inst = new Singleton;

线程安全相关问题:

饿汉模式在程序运行主函数之前就完成了单例对象的创建,由于main函数之前是不存在多线程的,因此饿汉模式下单例对象的创建过程是线程安全的

后续所有多线程要访问这个单例对象,都需要通过调用GetInstance函数来获取,这个获取过程是不需要加锁的,因为这是一个读操作

当然,如果线程通过GetInstance获取到单例对象后,要用这个单例对象进行一些线程不安全的操作,那么这时就需要加锁了

例如:

#include<map>
#include<string>
#include<iostream>
using namespace std;
class Singleton
{
public://提供获取单例对象的接口函数static Singleton& GetInstance(){return _sinst;}void func();void Add(const pair<string, string>& kv){_dict[kv.first] = kv.second;}void Print(){for (auto& e : _dict){cout << e.first << ":" << e.second << endl;}cout << endl;}private:// 1、构造函数私有Singleton(){// ...}// 3、防拷贝Singleton(const Singleton& s) = delete;Singleton& operator=(const Singleton& s) = delete;map<string, string> _dict;// 静态实例static Singleton _sinst;};Singleton   Singleton::_sinst;int main()
{//Singleton::GetInstance();cout << &Singleton::GetInstance() << endl;cout << &Singleton::GetInstance() << endl;cout << &Singleton::GetInstance() << endl;// Singleton copy(Singleton::GetInstance());Singleton::GetInstance().Add({ "xxx", "111" });Singleton::GetInstance().Add({ "yyy", "222" });Singleton::GetInstance().Add({ "zzzzz", "333" });Singleton::GetInstance().Add({ "abc", "333" });Singleton::GetInstance().Print();
}

懒汉模式

  1. 将构造函数设置为私有,并将拷贝构造函数和赋值运算符重载函数设置为私有或删除,防止外部创建或拷贝对象。
  2. 提供一个指向单例对象的static指针,并在程序入口之前先将其初始化为空。
  3. 提供一个全局访问点获取单例对象
class Singleton
{
public://3、提供一个全局访问点获取单例对象static Singleton* GetInstance(){//双检查if (_inst == nullptr){_mtx.lock();if (_inst == nullptr){_inst = new Singleton;}_mtx.unlock();}return _inst;}
private://1、将构造函数设置为私有,并防拷贝Singleton(){}Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;//2、提供一个指向单例对象的static指针static Singleton* _inst;static mutex _mtx; //互斥锁
};//在程序入口之前先将static指针初始化为空
Singleton* Singleton::_inst = nullptr;
mutex Singleton::_mtx; //初始化互斥锁

饿汉模式的优点就是简单,但是它的缺点也比较明显。饿汉模式在程序运行主函数之前就会创建单例对象,如果单例类的构造函数中所做的工作比较多,就会导致程序迟迟无法进入主函数,在外部看来就好像是程序卡住了。

此外,如果有多个单例类需要创建单例对象,并且它们之间的初始化存在某种依赖关系,比如单例对象A的创建必须在单例对象B之后,此时饿汉模式也会存在问题,因为我们无法保证这多个单例对象中的哪个对象先创建

而懒汉模式就能很好的解决上述饿汉模式的缺点,因为懒汉模式并不是一开始就完成单例对象的创建,因此不会导致程序迟迟无法进入主函数,并且懒汉模式中各个单例对象创建的顺序是由各个单例类中的GetInstance函数第一次被调用的顺序决定,因此是可控制的。
懒汉模式的缺点就是,在编码上比饿汉模式复杂,在创建单例对象时需要考虑线程安全的问题

单例场景

在 RPC(Remote Procedure Call,远程过程调用)项目中,单例模式是一种常见的设计模式,用于确保某个类只有一个实例,并提供一个全局访问点。单例模式在 RPC 项目中特别有用,例如用于管理配置、日志记录器或连接池等资源。

例如:在 RPC 项目中使用单例模式来管理一个全局的配置对象

#include <iostream>
#include <mutex>
#include <memory>class ConfigManager {
private:// 静态指针,存储唯一的实例static std::unique_ptr<ConfigManager> instance;// 私有化构造函数,防止外部直接构造ConfigManager() {std::cout << "ConfigManager initialized." << std::endl;}// 禁止拷贝构造和赋值操作ConfigManager(const ConfigManager&) = delete;ConfigManager& operator=(const ConfigManager&) = delete;public:// 提供一个静态方法获取实例static ConfigManager& getInstance() {static std::once_flag onceFlag;std::call_once(onceFlag, []() {instance = std::make_unique<ConfigManager>();});return *instance;}// 示例方法:获取配置值std::string getConfigValue(const std::string& key) {// 这里可以实现从配置文件或数据库中读取配置return "value_for_" + key;}
};// 初始化静态成员变量
std::unique_ptr<ConfigManager> ConfigManager::instance = nullptr;

使用单例

#include <iostream>int main() {// 获取单例实例ConfigManager& configManager = ConfigManager::getInstance();// 使用单例实例std::string value = configManager.getConfigValue("database_url");std::cout << "Config Value: " << value << std::endl;return 0;
}

代码理解:

  1. 私有化构造函数
    • ConfigManager():构造函数被私有化,防止外部直接构造对象。
    • 禁止拷贝构造和赋值操作,确保类的实例唯一性。
  2. 静态实例
    • static std::unique_ptr<ConfigManager> instance;:静态成员变量,存储唯一的实例。
    • 使用 std::unique_ptr 确保实例在程序结束时自动释放。
  3. 全局访问点
    • static ConfigManager& getInstance():提供一个静态方法,用于获取唯一的实例。
    • 使用 std::call_oncestd::once_flag 确保实例只被初始化一次,即使在多线程环境下也能安全工作。
  4. 延迟初始化
    • 实例仅在第一次调用 getInstance() 时初始化,避免不必要的资源占用。

http://www.ppmy.cn/server/170317.html

相关文章

Python--函数进阶(上)

1. 参数深入理解 1.1 参数传递的内存机制 Python中参数传递的是内存地址&#xff08;引用传递&#xff09;&#xff0c;而非值拷贝。这意味着&#xff1a; 可变对象&#xff08;列表、字典&#xff09;在函数内修改会影响外部变量。不可变对象&#xff08;数字、字符串&…

【从零开始学Redis】高级篇--超全总结笔记

Redis从入门到精通&#xff0c;超全笔记专栏 Hello&#xff0c;大家好&#xff0c;我是姜来可期&#xff08;全网同名&#xff09;&#xff0c;一名在读985转码大学生&#xff0c;一起学习&#xff0c;共同交流&#xff01;&#xff01;&#xff01; 分布式缓存 分布式缓存是…

5. Go 方法(结构体的方法成员)

Go语言没有传统的 class &#xff0c;为了让函数和结构体能够关联&#xff0c;Go引入了“方法”的概念。 当普通函数添加了接收者&#xff08;receiver&#xff09;后&#xff0c;就变成了方法。 一、函数和方法示例 // 普通函数 func Check(s string) string {return s }//…

内网网络安全的解决之道

本文简要分析了企业内部网络所面临的主要分析&#xff0c;阐述了安全管理人员针对不同威胁的主要技术应对措施。进一步介绍了业界各种技术措施的现状&#xff0c;并提出了未来可能的发展趋势。 内网网络安全问题的提出 网络安全对于绝大多数人而言指的都是互联网安全&#xff…

【DeepSeek与鸿蒙HarmonyOS:开启应用开发新次元】

引言&#xff1a;科技融合的新曙光 在当今数字化浪潮中&#xff0c;DeepSeek 和鸿蒙 HarmonyOS 宛如两颗璀璨的明星&#xff0c;各自在人工智能和操作系统领域熠熠生辉。DeepSeek 以其强大的大模型能力&#xff0c;在自然语言处理、代码生成等多个领域展现出卓越的性能&#x…

清影2.0(AI视频生成)技术浅析(五):音频处理技术

清影2.0 的 音频处理技术 是其视频生成平台的重要组成部分,主要用于生成与视频内容相匹配的音频,包括文本转语音(TTS)、音效合成和背景音乐合成。 1. 音频处理技术概述 清影2.0 的音频处理技术主要包括以下模块: 文本转语音(TTS):将文本转换为自然语音。 音效合成:生…

Android Studio安装配置及运行

一、下载Android Studio 官网下载&#xff1a;下载 Android Studio 和应用工具 - Android 开发者 | Android Developers 跳转到下载界面&#xff0c;选择同意条款&#xff0c;并点击下载&#xff0c;如图&#xff1a; 二、详细安装 双击下载的文件 三、配置Android Studio …

用DeepSeek零基础预测《哪吒之魔童闹海》票房——从数据爬取到模型实战

系列文章目录 1.元件基础 2.电路设计 3.PCB设计 4.元件焊接 5.板子调试 6.程序设计 7.算法学习 8.编写exe 9.检测标准 10.项目举例 11.职业规划 文章目录 **一、为什么要预测票房&#xff1f;****二、准备工作****三、实战步骤详解****Step 1&#xff1a;数据爬取与清洗&am…