本页内容

QGlobalStatic Struct

template <typename Holder> struct QGlobalStatic

QGlobalStatic 类用于实现全局静态对象。更多内容...

头文件: #include <QGlobalStatic>
CMake: find_package(Qt6 REQUIRED COMPONENTS Core)
target_link_libraries(mytarget PRIVATE Qt6::Core)
qmake: QT += core

注意:该结构体中的所有函数均是线程安全的。

公共类型

公共函数

bool exists() const
bool isDestroyed() const
operator QGlobalStatic<Holder>::Type *()
QGlobalStatic<Holder>::Type &operator*()
QGlobalStatic<Holder>::Type *operator->()

宏

Q_GLOBAL_STATIC(Type, variableName, ...)

详细说明

QGlobalStatic<Holder> 是一个模板类,其中Holder 是由Q_GLOBAL_STATIC() 宏生成的内部类型。可以通过Type typedef 访问该全局静态对象的用户可见类型。

QGlobalStatic 类是使用Q_GLOBAL_STATIC() 时导出的前端 API。有关该宏的要求及其使用场景的讨论,请参阅该宏的文档。

通常情况下,您不会直接使用该类,而是会像下面这样使用Q_GLOBAL_STATIC() 宏:

Q_GLOBAL_STATIC(MyType, myGlobal)

上述示例创建了一个名为myGlobal 的 QGlobalStatic 类型对象。在上述声明之后,myGlobal 对象可被视为指向MyType 类型对象的指针,且保证该对象仅被初始化一次。除了作为指针使用外,该对象还提供了两个方法来确定全局对象的当前状态:exists() 和isDestroyed()。

另请参阅 Q_GLOBAL_STATIC()。

成员类型文档

[alias] QGlobalStatic::Type

该类型等同于传递给Q_GLOBAL_STATIC() 或 Q_GLOBAL_STATIC_WITH_ARGS() 宏的Type 参数。它用于某些函数的返回类型中。

成员函数文档

[noexcept] bool QGlobalStatic::exists() const

如果全局静态对象已完成初始化(即该类型的构造函数已返回),但尚未完成销毁,则该函数返回true 。特别需要注意的是,如果初始化仍在进行中,该函数将返回false 。

一旦该函数返回 true,在全局静态对象被销毁之前,它将永远不会再次返回 false。全局静态对象的销毁发生在程序退出时,或者在包含该全局静态对象的插件或库被卸载时。

在程序执行的任何阶段调用此函数都是安全的:它不会失败,也不会导致死锁。此外,如果内容尚未创建,它也不会触发创建操作。

如果能够确定全局静态对象的初始条件,并且希望避免可能耗费资源的构造操作,则此函数非常有用。

例如,在下面的代码示例中,该函数用于短路名为 `globalState ` 的全局静态对象的创建,并返回默认值:

Q_GLOBAL_STATIC(MyType, globalState)
QString someState()
{
    if (globalState.exists())
        return globalState->someState;
    return QString();
}

线程安全说明:从任何线程在任何时候调用本函数,它都会返回有效的结果,因此本函数是线程安全的。但由于构造操作的非原子性,在构造完成后的一小段时间内,本函数可能会返回 false。

内存顺序注意事项:此函数不提供任何内存顺序保证。该保证由返回内容指针或引用的访问函数提供。如果您绕过访问函数并尝试访问由构造函数设置的全局状态,请务必使用QAtomicInt 或QAtomicPointer 提供的正确内存顺序语义。

另请参阅 isDestroyed()。

[noexcept] bool QGlobalStatic::isDestroyed() const

如果全局静态对象的销毁已经完成(即该类型的析构函数已经返回),则该函数返回true 。特别需要注意的是,如果销毁仍在进行中,则该函数返回false 。

一旦该函数返回 true,除非程序重新启动,或者包含该全局静态对象的插件或库被卸载并重新加载,否则它将永远不会再次返回 false。

在程序执行的任何阶段调用此函数都是安全的:它不会失败,也不会导致死锁。此外,如果相关内容尚未创建,此函数也不会触发其创建。

此函数在可能于程序关闭时执行的代码中非常有用,可用于确定是否仍可访问相关内容。

另请参阅 exists()。

QGlobalStatic::operator QGlobalStatic<Holder>::Type *()

该函数返回此全局静态变量的内容地址。如果内容尚未创建,该函数将以线程安全的方式创建它。如果内容已被销毁,该函数将返回一个空指针。

例如,可以使用此函数将全局静态变量的内容指针存储在局部变量中,从而避免多次调用该函数。Q_GLOBAL_STATIC() 的实现本身已经相当高效,但在对性能要求极高的代码段中,稍加协助编译器可能会有所帮助。例如:

Q_GLOBAL_STATIC(MyType, globalState)
QString someState()
{
    if (globalState::isDestroyed())
        return QString();
    MyType *state = globalState;
    if (state->condition)
        return state->value;
    else
        return state->worth;
}

另请参阅 operator->() 和operator*()。

QGlobalStatic<Holder>::Type &QGlobalStatic::operator*()

该函数返回对此全局静态变量的内容的引用。如果内容尚未创建,该函数将以线程安全的方式创建它们。

该函数不会检查内容是否已被销毁。如果在对象已被销毁后调用该函数,它将返回一个无效的引用,该引用绝不能被使用。

另请参阅 exists() 和isDestroyed()。

QGlobalStatic<Holder>::Type *QGlobalStatic::operator->()

该函数返回此全局静态变量的内容地址。如果内容尚未创建,该函数将以线程安全的方式创建它们。

该函数不会检查内容是否已被销毁,且永远不会返回 null。如果在对象已被销毁后调用此函数,它将返回一个悬空指针,请勿对其进行解引用。

另请参阅 exists() 和isDestroyed()。

宏文档

Q_GLOBAL_STATIC(Type, variableName, ...)

创建一个名为variableName 的全局静态对象,类型为QGlobalStatic 。该对象的行为相当于指向Type 的指针。由 Q_GLOBAL_STATIC 创建的对象会在首次使用时自动初始化,这意味着它不会增加应用程序或库的加载时间。此外,该对象在所有平台上均以线程安全的方式进行初始化。

自 Qt 6.3 起,该宏支持可变参数,这些参数用于初始化对象,从而消除了对 `Q_GLOBAL_STATIC_WITH_ARGS ` 的需求。请注意,与旧版宏不同,这些参数无需额外的圆括号。

该宏的典型用法如下,位于全局作用域中(即不在任何函数或类体内部):

Q_GLOBAL_STATIC(MyType, myGlobal)

该宏旨在替代非 POD(Plain Old Data,即按 C++11 术语而言,非由平凡类型构成的)的全局静态对象,因此得名。例如,以下 C++ 代码创建了一个全局静态变量:

static MyType myGlobal;

与 Q_GLOBAL_STATIC 相比,假设MyType 是一个具有构造函数、析构函数或以其他方式不属于 POD 的类或结构体,后者存在以下缺点:

  • 它要求在加载时对 `myGlobal ` 进行初始化(即在加载库或应用程序时会调用 `MyType ` 的默认构造函数);
  • 即使该对象从未被使用,它仍会被初始化;
  • 不同翻译单元之间的初始化和销毁顺序无法确定,这可能导致其他全局变量的构造函数或析构函数在该对象初始化之前或销毁之后对其进行操作。

Q_GLOBAL_STATIC 宏通过保证首次使用时的线程安全初始化,并允许用户查询该类型是否已被销毁,从而解决了所有这些问题,以避免“销毁后使用”的问题(参见QGlobalStatic::isDestroyed())。

构造函数和析构函数

对于 Q_GLOBAL_STATIC,当仅指定类型和变量名时,其Type 必须具有公开的默认构造函数且可公开销毁。 否则,Type 必须有一个公共构造函数,该构造函数接受宏的其余参数。对于 Q_GLOBAL_STATIC_WITH_ARGS(),必须有一个公共构造函数,该构造函数将宏的第三个参数作为其参数列表。

如果Type 的相关构造函数或析构函数为受保护(protected)或私有(private),则无法使用Q_GLOBAL_STATIC。 如果相关类型将这些成员声明为受保护(protected),可以通过继承该类型并创建公共构造函数和析构函数来解决此问题。如果该类型将它们声明为私有(private),则在继承之前必须进行朋友声明。

例如,以下代码足以基于先前定义的 `MyOtherType ` 创建 `MyType `,该类具有受保护的默认构造函数和/或受保护的析构函数(或者将它们声明为私有,但同时将 `MyType ` 声明为友元)。

class MyType : public MyOtherType { };
Q_GLOBAL_STATIC(MyType, myGlobal)

MyType 无需构造体,因为析构函数是隐式成员,且若未定义其他构造函数,默认构造函数也是隐式成员。然而,若要在Type 和variableName 之后使用带参数的构造函数,或与 Q_GLOBAL_STATIC_WITH_ARGS() 配合使用,则必须提供合适的构造函数体:

class MyType : public MyOtherType
{
public:
    MyType(int i) : MyOtherType(i) {}
};
Q_GLOBAL_STATIC(MyType, myGlobal, 42)

或者(由于 C++11 引入了继承构造函数),也可以这样写:

class MyType : public MyOtherType
{
public:
    using MyOtherType::MyOtherType;
};
Q_GLOBAL_STATIC_WITH_ARGS(MyType, myGlobal, (42))

放置

Q_GLOBAL_STATIC 宏会在全局作用域内创建一个类型,以及一个必然为静态的该类型变量。无法将 Q_GLOBAL_STATIC 宏放置在函数内部或类的体中(这样做会导致编译错误)。

更重要的是,该宏应置于源文件中,切勿置于头文件中。 由于生成的对象具有静态链接特性,如果将该宏放置在头文件中并被多个源文件包含,该对象将被多次定义,且不会引发链接错误。相反,每个翻译单元将引用不同的对象,这可能会导致难以察觉且难以追踪的错误。

请注意,不建议将该宏用于 POD 类型或具有 C++11 constexpr 构造函数(可简单构造和销毁)的类型。对于这些类型,仍建议使用常规的 static 声明,无论是全局的还是函数局部。

该宏虽然可以正常工作,但会增加不必要的开销。

构造时的可重入性、线程安全性、死锁及异常安全性

Q_GLOBAL_STATIC 宏会创建一个在首次使用时以线程安全方式自行初始化的对象:如果多个线程同时尝试初始化该对象,则仅有一个线程会继续进行初始化,而所有其他线程将等待初始化完成。

如果初始化过程中抛出异常,则初始化被视为未完成,并在控制流到达该对象的任何使用处时再次尝试初始化。如果有线程正在等待初始化,其中一个线程会被唤醒以尝试初始化。

该宏不保证来自同一线程的可重入性。如果从全局静态对象自身的构造函数内部直接或间接地访问该对象,则肯定会发生死锁。

此外,如果两个 Q_GLOBAL_STATIC 对象正在两个不同的线程上进行初始化,且各自的初始化序列会访问另一个对象,则可能会发生死锁。 因此,建议保持全局静态构造函数的简单性;若无法做到这一点,则应确保在构造过程中全局静态对象的使用之间不存在交叉依赖。

销毁

如果该对象在程序生命周期内从未被使用(除了QGlobalStatic::exists()和QGlobalStatic::isDestroyed()函数之外),则不会创建Type 类型的内容,也不会执行任何退出时操作。

如果对象被创建,它将在程序退出时被销毁,这与 C 语言中的atexit() 函数类似。事实上,在大多数系统上,如果库或插件在程序退出前从内存中卸载,销毁函数也会被调用。

由于销毁操作旨在程序退出时进行,因此不提供线程安全保障。这包括插件或库被卸载的情况。此外,由于析构函数不应抛出异常,因此也不提供异常安全保障。

不过,允许重入:在销毁过程中,可以访问全局静态对象,且返回的指针将与销毁开始前保持一致。销毁完成后,不允许访问全局静态对象,但QGlobalStatic API 中注明的例外情况除外。

另请参阅 Q_APPLICATION_STATIC() 和QGlobalStatic 。

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.