首页 > 其他分享 >Qt小知识2.Q_GLOBAL_STATIC

Qt小知识2.Q_GLOBAL_STATIC

时间:2023-12-13 14:22:05浏览次数:32  
标签:初始化 Qt 创建 GLOBAL STATIC 全局 日志

1 了解Q_GLOBAL_STATIC

Q_GLOBAL_STATIC 是 Qt 中提供的一个宏,用于创建跨越多个文件的全局静态对象。其主要作用在于两点:

  1. 懒惰初始化(Lazy initialization):它确保全局静态对象只有在首次使用时才被创建,而不是在程序启动时立即创建,从而可以减少程序启动时的初始化开销。
  2. 线程安全(Thread safety):在多线程环境中,Q_GLOBAL_STATIC 保证了全局静态对象的初始化是线程安全的,即使多个线程试图同时第一次访问它,对象也只会被创建一次。

2 实际应用

下面是一个使用 Q_GLOBAL_STATIC 的示例:

#include <QMutex>
#include <QDebug>
#include <QCoreApplication>

// 定义一个全局的互斥锁,用于跨线程同步访问
struct GlobalMutex {
    QMutex mutex;
};

Q_GLOBAL_STATIC(GlobalMutex, globalMutex)

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 当需要使用这个全局互斥锁时
    globalMutex()->mutex.lock();
    qDebug() << "Doing some thread-safe operation...";
    globalMutex()->mutex.unlock();

    return a.exec();
}

在这个例子中,我们定义了一个 GlobalMutex 结构体,包含一个 QMutex 对象。然后我们使用 Q_GLOBAL_STATIC 宏来创建一个全局静态的 GlobalMutex 实例,命名为 globalMutex。这个互斥锁可以在程序的任何地方使用,并保证只在首次使用时被初始化,同时保证了其初始化过程是线程安全的。

引用全局静态对象使用 globalMutex() 函数调用的方式(注意是一个函数调用语法),这是 Q_GLOBAL_STATIC 语法的特征,可以保证按需创建(懒惰初始化)并且是线程安全的。

使用 Q_GLOBAL_STATIC 的好处是它避免了程序中手动管理全局变量初始化顺序的复杂度,也消除了"SIOF - Static Initialization Order Fiasco"(静态初始化顺序问题)的风险,因为静态对象仅在首次访问时被创建,避免了因依赖其他全局对象在初始化时还未创建导致的问题。同时,当全局对象具有复杂的构造和析构过程时,使用 Q_GLOBAL_STATIC 可以确保安全地创建和清理资源。

Q_GLOBAL_STATIC 也经常用于需要在整个应用程序中访问的单例对象,例如日志工具、应用程序配置或者性能监控器等。以下是一个使用 Q_GLOBAL_STATIC 宏来创建和使用应用程序配置单例的例子:

#include <QString>
#include <QCoreApplication>

// 假设这是应用程序配置类
class AppConfig {
public:
    AppConfig() {
        // 加载或初始化配置
    }

    QString getValue(const QString &key) {
        // 假设从某处获取配置值
        return "Some Config Value";
    }
};

Q_GLOBAL_STATIC(AppConfig, appConfigInstance)

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    // 使用全局配置实例
    QString configValue = appConfigInstance()->getValue("someKey");
    // Do something with configValue

    return app.exec();
}

在这个例子中,AppConfig 类代表一个配置管理器,它负责加载、保存和获取应用程序配置。我们通过 Q_GLOBAL_STATIC 宏声明了一个 AppConfig 的全局静态实例 appConfigInstance。

然后,在 main 函数中,我们可以通过 appConfigInstance() 函数调用来访问这个全局配置实例,并从中获取配置值。和前例一样,这种访问方式保证了 AppConfig 的实例只有在首次使用时才创建,从而实现懒惰初始化,并且是线程安全的。

这样的做法特别适用于配置管理的场景,因为你往往需要在应用程序的多个位置访问和修改配置,而不希望每次都创建配置类的实例,Q_GLOBAL_STATIC 提供了一种方便的全局访问点。

3 了解Q_GLOBAL_STATIC_WITH_ARGS

Q_GLOBAL_STATIC_WITH_ARGS 是 Q_GLOBAL_STATIC 的一个变体,它允许使用参数来初始化全局静态对象。这意味着当你的全局静态对象需要在构造函数中传递一些参数来初始化时,Q_GLOBAL_STATIC_WITH_ARGS 就特别有用。

其语法与 Q_GLOBAL_STATIC 相似,但是它允许在宏的第二个参数中传入一个构造函数参数列表。

下面是使用 Q_GLOBAL_STATIC_WITH_ARGS 的一个示例:

#include <QString>
#include <QCoreApplication>

// 假设这是一个需要参数初始化的类
class Logger {
public:
    Logger(QString logFileName) {
        // 假设使用这个文件名初始化日志系统
        _logFileName = logFileName;
    }

    void log(const QString &message) {
        // 假设记录日志到文件
    }

private:
    QString _logFileName;
};

// 使用指定的日志文件名初始化全局日志对象
Q_GLOBAL_STATIC_WITH_ARGS(Logger, globalLogger, (QString("application.log")))

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    // 使用全局日志对象记录一条消息
    globalLogger()->log("Application started");

    return app.exec();
}

在这个例子中,Logger 类是一个日志记录器,它通过构造函数接收一个日志文件名来初始化。我们使用 Q_GLOBAL_STATIC_WITH_ARGS 宏创建了一个全局的 Logger 实例 globalLogger,并通过传递了一个参数 "application.log" 作为日志文件名进行初始化。

然后,在 main 函数中,我们使用 globalLogger() 来获取全局日志实例并记录一条消息,这与前面的 Q_GLOBAL_STATIC 示例类似。全局的 Logger 实例会在首次使用时进行懒惰初始化,并保证初始化的线程安全性。

通过这种方式,Q_GLOBAL_STATIC_WITH_ARGS 引入了构造函数参数,提供了更多的灵活性,用于初始化那些需要额外信息才能正确创建的全局静态对象。

4 总结

Q_GLOBAL_STATIC 提供了一个安全的模式来创建、使用和清理全局对象,这在大型应用程序中特别有用。它简化了单例模式的使用,并且避免了手动管理全局资源带来的复杂性和风险。

标签:初始化,Qt,创建,GLOBAL,STATIC,全局,日志
From: https://www.cnblogs.com/luoxiang/p/17898942.html

相关文章

  • C++ Qt开发:RadioButton单选框分组组件
    Qt是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍QRadioButton单选框组件以及与之交互的QButtonGroup类的常用方法及灵活运用。QRadioButton是Qt框......
  • iMX287A嵌入式Qt环境搭建
    原文:https://zhuanlan.zhihu.com/p/111021921?utm_id=01.嵌入式Qt简介Qt是一个跨平台的应用程序开发框架。使用Qt开发的应用程序,只需要编写一套代码,然后把这套代码放在不同平台的Qt环境去编译,就会生成可以运行在对应平台的应用程序。例如,我在Windows写了一个串口助手,这套代......
  • ubuntu安装qt4.8.6
    转载(https://blog.csdn.net/qq_26849933/article/details/127115646)文章目录前言一、查看GCC版本二、QT4库安装下载降低GCC编译器版本前期介绍具体实施QT4详细安装步骤参考链接前言ubuntu18.04及以后的版本(20.04,22.04)在编译QT4库的时候会报错,无......
  • 将QWebEngineView添加到QStackedWidget或QTabWidget中导致切换按钮失效的解决方案
    问题描述:将QWebEngineView添加到QStackedWidget或QTabWidget中导致切换按钮失效,如果只有两个来回切的话,是没有问题的,当出现多个页面的时候,就会切换失灵。解决思路:将QWebEngineView浮到上面,只要实现大小、位置、显示隐藏与主页面同步即可。 QWebEngineView窗口构造窗口添加:se......
  • 笔记:Qt开发之多线程的实现(QThread、moveToThread)
    目标:了解Qt实现多线程的两种基本方式(QThread、moveToThread),各自的实现方式、使用场景。1,子类化QThread实现方式:继承QThread类,重写run()函数实现多线程classWorkerThread:publicQThread{ Q_OBJECT public: explicitMyThread(QObject*parent=nullptr):QObject(pare......
  • 使用C++和QT实现Log自定义日志系统
    MyLog说明使用QT的qInstallMessageHandler函数结合qDebug,qInfo实现自定义的日志系统输出日志到文件和控制台自动检测日志文件大小自动更新日志文件修改日期自动备份自动删除一个月前的日志文件支持多线程程序支持扩展,可输出日志到数据库,网络,或服务器支持扩展,可使用co......
  • 笔记:Qt开发之定制化qDebug()函数
    目标:实现qDebug()函数的定制输出,包含文件名、函数名、行数等信息1,通过qSetMessagePattern函数,实现定制化输出intmain(intargc,char**argv){QApplicationapp(argc,argv);//改变缺省消息处理程序的输出,信息:线程:功能函数(行数):时间qSetMessagePattern("%{mes......
  • 【转载】QT学习之路(一)ubuntu 18.04的Qt Creator在线安装
    https://blog.csdn.net/qq_26849933/article/details/127115102前言Qt是嵌入式开发的必备工具之一,在Linux下安装尤其重要。Qt是C++的一个库,或者说是开发框架,里面集成了一些库函数,提高开发效率。QtCreator是一个IDE,就是一个平台,一个开发环境,类似的比如说VS,也可以进行Qt开发,当......
  • C++ Qt开发:SpinBox数值微调框组件
    Qt是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍QSpinBox精度数值组件的常用方法及灵活运用。QSpinBox是Qt框架中的一个部件(Widget),用于提供一个方......
  • Qt - 操作注册表
    一、写入注册表#include<QSettings>//实例QSettings//参数1:注册表位置//参数2:操作windows注册表QSettings::NativeFormat//说明:QSettings::IniFormat读写ini格式的配置文件,前面用过。QSettings*reg=newQSettings("HKEY_CURRENT_USER\\Software\\Qt01",QSett......