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

单例模式(C++)

单例模式

  • 一、核心原理
  • 二、常见的单例模式实现方式
    • 1. 懒汉式(Lazy Initialization)
    • 2. 饿汉式(Eager Initialization)
  • 三、关键实现细节解析
  • 四、单例模式的适用场景与特点
    • 使用场景
    • 特点

单例模式是一种常用的设计模式,其核心是确保一个类在全局只有唯一实例,并提供一个全局访问点。

一、核心原理

  1. 限制实例化:通过私有化类的构造函数、拷贝构造函数和赋值运算符,禁止外部直接创建实例或复制实例。
  2. 唯一实例:在类内部维护一个静态的自身实例指针,确保全局只有一个实例。
  3. 全局访问:提供一个静态的公开接口(如 getInstance()),让外部通过该接口获取唯一实例。

二、常见的单例模式实现方式

1. 懒汉式(Lazy Initialization)

实例在第一次被使用时才创建(延迟初始化),节省资源。

#include <QMutex>
#include <QScopedPointer>class Singleton {
public:// 全局访问点:获取唯一实例static Singleton& getInstance() {// 双重检查锁定(DCLP),避免多线程下重复创建if (m_instance.isNull()) {QMutexLocker locker(&m_mutex); // 加锁,确保线程安全if (m_instance.isNull()) {m_instance.reset(new Singleton()); // 首次调用时创建实例}}return *m_instance;}// 示例:单例提供的功能方法void doSomething() {// ... 业务逻辑 ...}private:// 私有化构造函数:禁止外部创建实例Singleton() {}// 私有化拷贝构造和赋值运算符:禁止复制Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;// 静态成员:存储唯一实例static QScopedPointer<Singleton> m_instance;static QMutex m_mutex; // 互斥锁,确保多线程安全
};// 初始化静态成员(类外定义)
QScopedPointer<Singleton> Singleton::m_instance(nullptr);
QMutex Singleton::m_mutex;

2. 饿汉式(Eager Initialization)

实例在程序启动时(类加载时)就创建,避免多线程同步问题,但可能提前占用资源。

class Singleton {
public:// 全局访问点:直接返回预创建的实例static Singleton& getInstance() {static Singleton instance; // 静态局部变量,程序启动时初始化return instance;}void doSomething() {// ... 业务逻辑 ...}private:// 私有化构造函数Singleton() {}// 禁止复制Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;
};

三、关键实现细节解析

  1. 私有化构造函数
    private 权限的构造函数阻止外部通过 new Singleton()Singleton obj 创建实例,确保实例只能在类内部创建。

  2. 禁止复制和赋值
    通过 = delete 显式删除拷贝构造函数和赋值运算符,避免外部通过 Singleton obj = Singleton::getInstance() 复制实例,保证唯一性。

  3. 静态实例与全局访问
    类内部的静态成员(m_instance 或静态局部变量)存储唯一实例,getInstance() 静态方法提供全局访问入口,确保任何地方都能获取同一个实例。

  4. 线程安全处理

    • 懒汉式中使用 QMutex 加锁,避免多线程同时调用 getInstance() 时创建多个实例(双重检查锁定进一步优化性能)。
    • 饿汉式依赖静态变量的初始化特性(C++11 后静态局部变量初始化是线程安全的),无需额外加锁。

四、单例模式的适用场景与特点

使用场景

  • 全局配置管理(如程序的配置类)。
  • 日志工具类(确保日志写入的唯一性)。
//ErrorLogger.h文件
#ifndef ERRORLOGGER_H
#define ERRORLOGGER_H#include <QString>
#include <QMutex>// 错误日志工具类(单例模式)
class ErrorLogger
{
public:// 获取单例实例static ErrorLogger& getInstance();// 禁止拷贝和赋值ErrorLogger(const ErrorLogger&) = delete;ErrorLogger& operator=(const ErrorLogger&) = delete;// 写入错误日志void writeLog(const QString& errorMessage);// 设置日志文件路径(默认当前目录下的error.log)void setLogFilePath(const QString& path);private:// 私有构造函数(单例模式)ErrorLogger();QString m_logFilePath; // 日志文件路径QMutex m_mutex;       // 互斥锁,确保多线程安全
};#endif // ERRORLOGGER_H//ErrorLogger.cpp文件
#include "ErrorLogger.h"
#include <QFile>
#include <QTextStream>
#include <QDateTime>
#include <QDir>
#include <QDebug>ErrorLogger::ErrorLogger()
{// 默认日志路径:当前程序目录下的error.logm_logFilePath = QDir::currentPath() + "/error.log";
}ErrorLogger& ErrorLogger::getInstance()
{static ErrorLogger instance;return instance;
}void ErrorLogger::setLogFilePath(const QString& path)
{m_logFilePath = path;
}void ErrorLogger::writeLog(const QString& errorMessage)
{// 多线程加锁,避免日志写入冲突QMutexLocker locker(&m_mutex);// 获取当前时间戳(格式:yyyy-MM-dd hh:mm:ss)QString timeStamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");// 构建日志内容(时间 + 错误信息)QString logContent = QString("[%1] Error: %2\n").arg(timeStamp).arg(errorMessage);// 打开文件(以追加模式,不存在则创建)QFile file(m_logFilePath);if (!file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {qDebug() << "无法写入日志文件:" << file.errorString();return;}// 写入日志QTextStream out(&file);out << logContent;file.close();
}//main.cpp文件
// 写入错误日志(包含系统错误信息)ErrorLogger::getInstance().writeLog(QString("文件打开失败: %1(路径:%2)").arg(file.errorString()).arg(file.fileName()));
// 可选:设置自定义日志路径(如程序数据目录)ErrorLogger::getInstance().setLogFilePath(QDir::homePath() + "/myapp/logs/error.log");
  • 设备管理器(如硬件设备的唯一控制实例)。
  • 缓存管理器(避免重复创建缓存对象)。

特点

  • 优点
    确保全局唯一实例,减少资源消耗(如频繁创建销毁实例的开销),提供统一的访问点。

  • 缺点
    单例本质是全局变量,可能导致代码耦合度升高;测试困难(单例状态难以隔离);在多线程环境下需谨慎处理同步问题。

通过上述实现,单例模式能有效控制类的实例数量,在需要全局唯一访问点的场景中非常实用。


文章转载自:

http://UCKt6tf4.npkrm.cn
http://Ck2RPGy8.npkrm.cn
http://sppPjYbI.npkrm.cn
http://BKnihOtO.npkrm.cn
http://BauJKEwn.npkrm.cn
http://a5h5I3re.npkrm.cn
http://RCSWGkj7.npkrm.cn
http://ADUHZ2CI.npkrm.cn
http://oU10Lyyz.npkrm.cn
http://GRWWW7FZ.npkrm.cn
http://v7KEtfiL.npkrm.cn
http://K3muC1Fr.npkrm.cn
http://pjXfsBll.npkrm.cn
http://fxpdOJ54.npkrm.cn
http://BPJvfJHI.npkrm.cn
http://YrfXSARf.npkrm.cn
http://Jzz5HRlW.npkrm.cn
http://7128Bn9B.npkrm.cn
http://Fxs6Yj0G.npkrm.cn
http://TARUb6Mg.npkrm.cn
http://kNHVVNPY.npkrm.cn
http://RhsflmfI.npkrm.cn
http://S2Ll7APG.npkrm.cn
http://lEMmzVM7.npkrm.cn
http://zVjECk5Q.npkrm.cn
http://me8gKUr6.npkrm.cn
http://Fp0suejA.npkrm.cn
http://3cgmpQde.npkrm.cn
http://momn9VgH.npkrm.cn
http://jDGyjXaz.npkrm.cn
http://www.dtcms.com/a/375200.html

相关文章:

  • All in AI之二:数学体系的建立
  • 【Python】S1 基础篇 P5 字典模块指南
  • MySQL底层架构设计原理详细介绍
  • 《ServiceMesh落地避坑指南:从智慧园区故障看Envoy配置治理》
  • 【ARMv7-M】复位向量与启动过程
  • SQL面试题及详细答案150道(136-150) --- 性能优化与数据库设计篇
  • CMake Qt程序打包与添加图标详细教程
  • 【MySQL】mysql-connector-cpp使用
  • Oracle RAC认证矩阵:规避风险的关键指南
  • CTF-Web手的百宝箱
  • Django高效查询:values_list实战详解
  • Redis核心数据结构
  • 海外代理IP平台Top3评测:LoongProxy、神龙动态IP、IPIPGO哪家更适合你?
  • 开发避坑指南(43):idea2025.1.3版本启动springboot服务输入jvm参数解决办法
  • Vue3入门到实战,最新版vue3+TypeScript前端开发教程,笔记03
  • 四元数 (Quaternion)与李群SE(3)知识点(1)
  • 【Java】NIO 简单介绍
  • Qt从小白到进阶:完整学习路线与资源指南(补充)
  • 结合大数据知识体系对仓库建模方法总结
  • AI 辅助文档生成:从接口注释到自动化 API 文档上线
  • Day 18: 多模态大模型专项 - 理论深度与面试精通之路
  • Flink Checkpoint失败问题分析与解决方案
  • Flyway:一款免费开源的数据库变更管理工具
  • 如何开发一个教育性质的多线程密码猜测演示器
  • 基于MATLAB的线性判别分析(LDA)人脸识别实现
  • iOS现有项目采用混合工程方式集成RN0.77.3版本
  • 软件设置linux时区,Linux设置和修改时间与时区
  • 系统架构设计师备考第18天——信息安全基础知识
  • 嵌入式系统学习Day36(简单的网页制作)
  • 【人工智能99问】GPT4与QWen3的对比(39/99)