QGlobalStatic Struct

template <typename Holder> struct QGlobalStatic

The QGlobalStatic class is used to implement a global static object. More...

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

Note: All functions in this struct are thread-safe.

Public Types

Public Functions

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

Macros

Q_GLOBAL_STATIC(Type, variableName, ...)

Detailed Description

The QGlobalStatic class is the front-end API exported when Q_GLOBAL_STATIC() is used. See the documentation of the macro for a discussion of its requirements and when to use it.

Normally, you will never use this class directly, but instead you will use the Q_GLOBAL_STATIC() macro, as follows:

Q_GLOBAL_STATIC(MyType, myGlobal)

The above example creates an object of type QGlobalStatic called myGlobal. After the above declaration, the myGlobal object may be used as if it were a pointer to an object of type MyType, guaranteed to be initialized exactly once. In addition to the use as a pointer, the object offers two methods to determine the current status of the global: exists() and isDestroyed().

See also Q_GLOBAL_STATIC() and Q_GLOBAL_STATIC_WITH_ARGS().

Member Type Documentation

[alias] QGlobalStatic::Type

This type is equivalent to the Type parameter passed to the Q_GLOBAL_STATIC() or Q_GLOBAL_STATIC_WITH_ARGS() macros. It is used in the return types of some functions.

Member Function Documentation

[noexcept] bool QGlobalStatic::exists() const

This function returns true if the global static object has already completed initialization (that is, if the constructor for the type has already returned) and has not yet completed destruction. In particular, note that this function returns false if the initialization is still in progress.

Once this function has returned true once, it will never return false again until the global static object is destroyed. The latter happens on program exit or when the plugin or library containing the global static is unloaded.

This function is safe to call at any point in the program execution: it cannot fail and cannot cause a deadlock. Additionally, it will not cause the contents to be created if they have not yet been created.

This function is useful if one can determine the initial conditions of the global static object and would prefer to avoid a possibly expensive construction operation.

For example, in the following code sample, this function is used to short-circuit the creation of the global static called globalState and returns a default value:

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

Thread-safety notice: this function is thread-safe in the sense that it may be called from any thread at any time and will always return a valid reply. But due to the non-atomic nature of construction, this function may return false for a short time after the construction has completed.

Memory ordering notice: this function does not impose any memory ordering guarantees. That is instead provided by the accessor functions that return the pointer or reference to the contents. If you bypass the accessor functions and attempt to access some global state set by the constructor, be sure to use the correct memory ordering semantics provided by QAtomicInt or QAtomicPointer.

See also isDestroyed().

[noexcept] bool QGlobalStatic::isDestroyed() const

This function returns true if the global static object has already completed destruction (that is, if the destructor for the type has already returned). In particular, note that this function returns false if the destruction is still in progress.

Once this function has returned true once, it will never return false again until either the program is restarted or the plugin or library containing the global static is unloaded and reloaded.

This function is safe to call at any point in the program execution: it cannot fail and cannot cause a deadlock. Additionally, it will not cause the contents to be created if they have not yet been created.

This function is useful in code that may be executed at program shutdown, to determine whether the contents may still be accessed or not.

See also exists().

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

This function returns the address of the contents of this global static. If the contents have not yet been created, they will be created thread-safely by this function. If the contents have already been destroyed, this function will return a null pointer.

This function can be used, for example, to store the pointer to the contents of the global static in a local variable, thus avoiding multiple calls to the function. The implementation of Q_GLOBAL_STATIC() is quite efficient already, but in performance-critical sections it might be useful to help the compiler a little. For example:

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;
}

See also operator->() and operator*().

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

This function returns a reference to the contents of this global static. If the contents have not yet been created, they will be created thread-safely by this function.

This function does not check if the contents have already been destroyed. If this function is called after the object has been destroyed, it will return an invalid reference that must not be used.

See also exists() and isDestroyed().

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

This function returns the address of the contents of this global static. If the contents have not yet been created, they will be created thread-safely by this function.

This function does not check if the contents have already been destroyed and will never return null. If this function is called after the object has been destroyed, it will return a dangling pointer that should not be dereferenced.

See also exists() and isDestroyed().

Macro Documentation

Q_GLOBAL_STATIC(Type, variableName, ...)

Creates a global and static object of type QGlobalStatic, named variableName. It behaves as a pointer to Type. The object created by Q_GLOBAL_STATIC initializes itself on the first use, which means that it will not increase the application or the library's load time. Additionally, the object is initialized in a thread-safe manner on all platforms.

Since Qt 6.3, this macro admits variadic arguments, which are used to initialize the object, thus making the need for Q_GLOBAL_STATIC_WITH_ARGS unnecessary. Please note the arguments do not require an extra set of parentheses, unlike the older macro.

The typical use of this macro is as follows, in a global context (that is, not inside any function or class body):

Q_GLOBAL_STATIC(MyType, myGlobal)

This macro is intended to replace global static objects that are not POD (Plain Old Data, or in C++11 terms, not made of a trivial type), hence the name. For example, the following C++ code creates a global static:

static MyType myGlobal;

Compared to Q_GLOBAL_STATIC, and assuming that MyType is a class or struct that has a constructor, a destructor, or is otherwise non-POD, the latter has the following drawbacks:

  • it requires load-time initialization of myGlobal (that is, the default constructor for MyType is called when the library or application is loaded);
  • the object will be initialized even if it is never used;
  • the order of initialization and destruction among different translation units is not determined, leading to possible uses, before initialization or after destruction, by the constructors or destructors of other global variables.

The Q_GLOBAL_STATIC macro solves all of these problems by guaranteeing thread-safe initialization on first use and allowing the user to query for whether the type has already been destroyed, to avoid the use-after-destruction problem (see QGlobalStatic::isDestroyed()).

Constructor and Destructor

For Q_GLOBAL_STATIC, when only given a type and variable name, its Type must be publicly default-constructible and publicly destructible. Otherwise, Type must have a public constructor that accepts the remaining arguments to the macro. For Q_GLOBAL_STATIC_WITH_ARGS(), there must be a public constructor that accepts the macro's third argument as its list of parameters.

It is not possible to use Q_GLOBAL_STATIC with a Type whose relevant constructor or destructor is protected or private. If the type in question declares those members protected, it is possible to overcome the issue by deriving from the type and creating a public constructor and destructor. If the type declares them private, a friend declaration is necessary before deriving.

For example, the following is enough to create MyType based on a previously-defined MyOtherType which has a protected default constructor and/or a protected destructor (or declares them private, but also declares MyType as a friend).

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

No body for MyType is required since the destructor is an implicit member and so is the default constructor if no other constructors are defined. For use with arguments after Type and variableName, or with Q_GLOBAL_STATIC_WITH_ARGS(), however, a suitable constructor body is necessary:

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

Alternatively (since C++11 introduced inheriting constructors), one could write:

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

Placement

The Q_GLOBAL_STATIC macro creates a type, and a variable of that type that is necessarily static, at the global scope. It is not possible to place the Q_GLOBAL_STATIC macro inside a function or the body of a class (doing so will result in compilation errors).

More importantly, this macro should be placed in source files, never in headers. Since the resulting object has static linkage, if the macro is placed in a header and included by multiple source files, the object will be defined multiple times and will not cause linking errors. Instead, each translation unit will refer to a different object, which could lead to subtle and hard-to-track errors.

Note that the macro is not recommended for use with types that are POD or that have C++11 constexpr constructors (trivially constructible and destructible). For those types, it is still recommended to use regular static, whether global or function-local.

This macro will work, but it will add unnecessary overhead.

Reentrancy, Thread-safety, Deadlocks, and Exception-safety on Construction

The Q_GLOBAL_STATIC macro creates an object that initializes itself on first use in a thread-safe manner: if multiple threads attempt to initialize the object at the same time, only one thread will proceed to initialize, while all other threads wait for completion.

If the initialization process throws an exception, the initialization is deemed not complete and will be attempted again when control reaches any use of the object. If there are any threads waiting for initialization, one of them will be woken up to attempt to initialize.

The macro makes no guarantee about reentrancy from the same thread. If the global static object is accessed directly or indirectly from inside its own constructor, a deadlock will surely happen.

In addition, if two Q_GLOBAL_STATIC objects are being initialized on two different threads and each one's initialization sequence accesses the other, a deadlock might happen. For that reason, it is recommended to keep global static constructors simple or, failing that, to ensure that there's no cross-dependency of uses of global static during construction.

Destruction

If the object is never used during the lifetime of the program, aside from the QGlobalStatic::exists() and QGlobalStatic::isDestroyed() functions, the contents of type Type will not be created and there will not be any exit-time operation.

If the object is created, it will be destroyed at exit-time, similar to the C atexit() function. On most systems, in fact, the destructor will also be called if the library or plugin is unloaded from memory before exit.

Since the destruction is meant to happen at program exit, no thread-safety is provided. This includes the case of plugin or library unload. In addition, since destructors are not supposed to throw exceptions, no exception safety is provided either.

However, reentrancy is permitted: during destruction, it is possible to access the global static object and the pointer returned will be the same as it was before destruction began. After the destruction has completed, accessing the global static object is not permitted, except as noted in the QGlobalStatic API.

See also Q_GLOBAL_STATIC_WITH_ARGS(), Q_APPLICATION_STATIC(), and QGlobalStatic.

© 2024 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.