單例模式(C++)(錯誤日志實現)

單例模式

  • 一、核心原理
  • 二、常見的單例模式實現方式
    • 1. 懶漢式(Lazy Initialization)
    • 2. 餓漢式(Eager Initialization)
  • 三、關鍵實現細節解析
  • 四、單例模式的適用場景與特點
    • 使用場景
      • 日志工具(確保日志寫入的唯一性)。
        • spdlog第三方庫實現
          • 使用步驟
    • 特點

單例模式是一種常用的設計模式,其核心是確保一個類在全局只有唯一實例,并提供一個全局訪問點。

一、核心原理

  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");
spdlog第三方庫實現

鏈接: C++日志記錄庫SPDLog簡介
spdlog學習—安裝及基本使用
spdlog是一個高性能、超快速、零配置的C++日志庫,它旨在提供簡潔的API和豐富的功能,同時保持高性能的日志記錄。它支持多種輸出目標、格式化選項、線程安全以及異步日志記錄。

  • 高性能:spdlog專為速度而設計,即使在高負載情況下也能保持良好的性能
  • 零配置:無需復雜的配置,只需包含頭文件即可在項目中使用
  • 異步日志:支持異步日志記錄,減少對主線程的影響
  • 格式化:支持自定義日志消息的格式化,包括時間戳、線程ID、日志級別等
  • 多平臺:跨平臺兼容,支持Windows、Linux、MacOS等操作系統
  • 豐富的API:提供豐富的日志級別和操作符重載,方便記錄各種類型的日志
  • 多目標輸出:可以將日志輸出到控制臺、普通文本文件、循環寫入文件(rotating log files)、每日生成新文件(daily logs)、系統日志等目標,同時也支持異步寫入以提高性能。
  • 豐富的日志級別:Spdlog 支持常見的日志級別,如 TRACE、DEBUG、INFO、WARN、ERROR、CRITICAL 等,用戶可以根據需要選擇不同級別的日志輸出。
  • 條件日志:根據預定義的條件開關,可以動態啟用或禁用特定級別的日志輸出。
使用步驟

spdlog庫的使用也非常簡單,只需要下載源代碼,然后把根目錄下的include目錄下的文件拷貝到我們的工程下,在工程中包含相應的頭文件即可。

  • 控制臺打印
  #include <spdlog/spdlog.h>#include <string.h>#include <iostream>int main(){// 普通打印spdlog::info("Welcome to info spdlog!");// 格式化打印// 打印字符串spdlog::info("Hello World {}", "spdlog!");// 打印數字spdlog::error("spdlog errCode : {}", -10020);// 指定打印數字的占位符spdlog::warn("spdlog format char {:08d}", 12);// 格式化打印不同進制的數據spdlog::critical("Support for int:{0:d} hex:{0:x} oct:{0:o} bin:{0:b}", 42);// 打印浮點型數據spdlog::info("float args are {:03.2f}", 1.23456);// 打印多個參數spdlog::info("string args are {0} {1}..", "too", "supported");spdlog::info("number args are {0} {1} {2}..", 10020, 10040, -100);system("pause");}

在這里插入圖片描述

  • 在文件中打印日志
  #include <spdlog/spdlog.h>#include <spdlog/sinks/basic_file_sink.h>#include <string.h>#include <iostream>int main(){try{// 參數1 日志標識符, 參數2 日志文件名std::shared_ptr<spdlog::logger> mylogger = spdlog::basic_logger_mt("spdlog", "spdlog.log");// 設置日志格式. 參數含義: [日志標識符] [日期] [日志級別] [線程號] [數據]mylogger->set_pattern("[%n][%Y-%m-%d %H:%M:%S.%e] [%l] [%t]  %v");mylogger->set_level(spdlog::level::debug);spdlog::flush_every(std::chrono::seconds(5)); // 定期刷新日志緩沖區mylogger->trace("Welcome to info spdlog!");mylogger->debug("Welcome to info spdlog!");mylogger->info("Welcome to info spdlog!");mylogger->warn("Welcome to info spdlog!");mylogger->error("Welcome to info spdlog!");mylogger->critical("Welcome to info spdlog!");// 刷新mylogger->flush_on(spdlog::level::debug);}catch (const spdlog::spdlog_ex& ex){std::cout << "Log initialization failed: " << ex.what() << std::endl;}system("pause");}

執行結果。執行程序后就會在當前目錄下生成一個spdlog.log文件,看下打印內容
在這里插入圖片描述

特點

  • 優點
    確保全局唯一實例,減少資源消耗(如頻繁創建銷毀實例的開銷),提供統一的訪問點。

  • 缺點
    單例本質是全局變量,可能導致代碼耦合度升高;測試困難(單例狀態難以隔離);在多線程環境下需謹慎處理同步問題。

通過上述實現,單例模式能有效控制類的實例數量,在需要全局唯一訪問點的場景中非常實用。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/96072.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/96072.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/96072.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

stm32 鏈接腳本沒有 .gcc_except_table 段也能支持 C++ 異常

stm32 使用 cubemx 生成的 gnu ld 鏈接腳本沒有 .gcc_except_table 段。如下所示 /* ****************************************************************************** ** ** file : LinkerScript.ld ** ** author : Auto-generated by STM32CubeIDE ** ** Abst…

SpringBoot改造MCP服務器(StreamableHTTP)

項目地址&#xff1a; https://gitee.com/kylewka/smart-ai 1 項目說明 MCP&#xff08;Model Context Protocol&#xff09;協議是一個用于 AI 模型和工具之間通信的標準協議。隨著 AI 應用變得越來越復雜并被廣泛部署&#xff0c;原有的通信機制面臨著一系列挑戰。 近期 MCP …

【數學建模】煙幕干擾彈投放策略優化:模型與算法整合框架

煙幕干擾彈投放策略優化&#xff1a;模型與算法整合框架 基于文獻研究和問題需求分析&#xff0c;我們構建了完整的模型與算法整合框架。 一、整體建模框架 1. 核心問題分解 物理層&#xff1a;煙幕彈道運動與擴散特性建模博弈層&#xff1a;導彈識別與決策機制建模優化層&…

結合大數據知識體系對倉庫建模方法總結

傳統的倉庫建模理論&#xff08;如維度建模&#xff09;仍然是基石&#xff0c;但大數據的“4V”特性&#xff08;Volume, Velocity, Variety, Value&#xff09;要求我們對這些方法進行演進和補充。 以下是結合大數據知識體系對倉庫建模方法的總結&#xff1a;一、核心目標&am…

C 語言第一課:hello word c

C 語言第一課&#xff1a;hello word c開發工具創建項目快速學習平臺開發工具 個人推薦使用 jetBrains 公司的 CLion 開發工具下載地址 https://www.jetbrains.com/clion/ 創建項目 編寫代碼 //頭文件 #include <stdio.h>//程序入口 int main(){printf("hello w…

基于Java Spring Boot的云原生TodoList Demo 項目,驗證云原生核心特性

以下是一個基于 Java Spring Boot 的云原生 TodoList Demo 項目&#xff0c;涵蓋 容器化、Kubernetes 編排、CI/CD、可觀測性、彈性擴縮容 等核心云原生特性&#xff0c;代碼簡潔且附詳細操作指南&#xff0c;適合入門學習。項目概覽 目標&#xff1a;實現一個支持增刪改查&…

開源一個輕量級 Go 工具庫:go-commons

項目背景 在日常 Go 開發中&#xff0c;我們經常需要處理字符串操作和系統監控相關的功能。雖然 Go 標準庫提供了基礎的字符串處理能力&#xff0c;但在實際項目中&#xff0c;我們往往需要一些更便捷的工具函數來提高開發效率。 基于"盡可能不使用第三方依賴"的原…

clang(clangd)與arm-linux-gcc、ARMGCC、ICCARM(IAR)、C51編譯器的兼容性

環境&#xff1a;vscodeclangdEIDE開發開發單片機&#xff08;C51 keilMDK IAR&#xff09;。 vscode遠程clangdarm-linux-gcc(交叉編譯工具鏈)。 &#xff08;1&#xff09;首先clang&#xff08;clangd&#xff09;是兼容gcc的&#xff0c;也就是兼容arm-linux-gcc&#xff…

Docker 部署 Rancher2.4.4

獲取2.4.4鏡像包docker pull rancher/rancher:v2.4.4創建目錄并賦予權限mkdir -p /home/rancher/{data,log} && chmod -R 777 /home/rancher啟動容器docker run -d \ --privileged \ --name rancher \ --restartunless-stopped \ -p 80:80 -p 443:443 \ -v /home/ranc…

無root使用adb模式下的scene 用shizuku激活scene教程

本次教程是用shizuku和ShizukuRunner激活scene的adb模式&#xff0c;實現大部分功能&#xff0c;比較簡單&#xff0c;如果手機已經root直接使用root模式即可。 工具 scene(點我下載) Shizuku(點我下載) ShizukuRunner(點我下載) 教程 1.首先要有一臺支持無線調試的手機(安…

《UE5_C++多人TPS完整教程》學習筆記50 ——《P51 多人游戲中的俯仰角(Pitch in Multiplayer)》

本文為B站系列教學視頻 《UE5_C多人TPS完整教程》 —— 《P51 多人游戲中的俯仰角&#xff08;Pitch in Multiplayer&#xff09;》 的學習筆記&#xff0c;該系列教學視頻為計算機工程師、程序員、游戲開發者、作家&#xff08;Engineer, Programmer, Game Developer, Author&…

樹莓派 Ubuntu 24.04 開機換源總結

1. 圖形界面 (桌面版) 如果你刷的是 Ubuntu Desktop 24.04&#xff1a;打開 Software & Updates&#xff08;軟件和更新&#xff09;。在 Ubuntu Software 標簽里找到 Download from 下拉菜單。默認只有 Main server 和 Server for China&#xff0c;如果想要更多選擇&…

工業顯示器在地鐵電力監控與運維中的應用

在地鐵電力監控與運維中&#xff0c;工業顯示器憑借其高可靠性、環境適應性和強大的功能集成&#xff0c;成為保障地鐵供電系統安全穩定運行的核心設備。以下從關鍵應用場景、技術優勢及實際案例三個維度展開分析&#xff1a;一、核心應用場景變配電室與環控電控室監控 工業顯示…

Docker 快速部署單節點 NiFi 1.27

Docker 快速部署單節點 NiFi 1.27 前言 Apache NiFi 是一款強大的數據集成工具&#xff0c;專注于數據的采集、處理和分發&#xff0c;具有可視化流程設計、強大的容錯能力等特點。通過 Docker 部署可以快速搭建環境&#xff0c;省去復雜的配置步驟。本文介紹如何使用官方鏡像…

php redis 中文API文檔手冊

php redis 中文API文檔手冊 Redis::__construct構造函數 $redis new Redis();connect, open 鏈接redis服務 參數 host: string&#xff0c;服務地址 port: int,端口號 timeout: float,鏈接時長 (可選, 默認為 0 &#xff0c;不限鏈接時間) 注: 在redis.conf中也有時間&#xf…

Windows環境下實現GitLab與Gitee倉庫代碼提交隔離

1. 背景 在開發工作中&#xff0c;我需要同時使用2個代碼托管平臺&#xff1a;公司統一使用的GitLab和個人學習用的 Gitee。我希望能夠在同一臺電腦上方便地管理和提交兩個平臺的代碼&#xff0c;實現賬號和提交內容的有效隔離。 前提條件&#xff1a; 已安裝Git Bash、Tort…

深度解析:抗輻射電源芯片 ASP4644S2B 在空間環境中的單粒子效應表現

摘要&#xff1a;隨著航天技術的飛速發展&#xff0c;空間電子設備面臨著日益復雜和嚴苛的輻射環境挑戰。單粒子效應&#xff08;SEE&#xff09;作為輻射環境對半導體器件影響的主要形式之一&#xff0c;極大地影響著航天電子系統的可靠性和穩定性。本文通過系統梳理國科安芯推…

【RabbitMQ】如何在 Ubuntu 安裝 RabbitMQ

1. 安裝部署 Erlang 環境 RabbitMQ 是一套開源的消息隊列服務軟件&#xff0c;基于 Erlang 語言編寫的&#xff0c;因此&#xff0c;在安裝 RabbitMQ 之前&#xff0c;我們需要先部署 Erlang 環境&#xff0c;再安裝 RabbitMQ 環境&#xff08;就像運行 Java 程序&#xff0c;…

vue集成高德地圖API工具類封裝

import axios, { AxiosInstance, AxiosResponse } from axios;// 高德地圖 API 響應基礎結構 interface AMapResponse {status: string;info: string;infocode: string; }// 逆地理編碼響應結構 interface RegeoResponse extends AMapResponse {regeocode: {formatted_address:…

手寫 Tomcat

文章目錄02 初出茅廬:構造一個極簡的 HttpServerRequestResponseHttpServer03 動態 Response : 按照規范構造返回流04 各司其職的 Server : 拆分響應模塊與處理模塊HttpConnectorHttpProcessor05 Server 性能提升: 設計多個 ProcessorHttpConnectorHttpProcessor06 規范化: 引入…