QGlobalStatic Struct
template <typename Holder> struct QGlobalStaticThe 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 for the macro for a discussion on when to use it and its requirements.
Normally, you will never use this class directly, but instead you will use the Q_GLOBAL_STATIC() or Q_GLOBAL_STATIC_WITH_ARGS() macros, 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 used as if it were a pointer, 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 specific, 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() { MyType *state = globalState; if (!state) { // we're in a post-destruction state return QString(); } if (state->condition) return state->value1; else return state->value2; }
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.
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.
Macro Documentation
Q_GLOBAL_STATIC(Type, VariableName, ...)
Creates a global and static object of type QGlobalStatic, of name VariableName and that 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, outside of any function bodies):
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 above has the following drawbacks:
- it requires load-time initialization of
MyType
(that is, the default constructor forMyType
is called when the library or application is loaded); - the type 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;
The Q_GLOBAL_STATIC macro solves all of the above 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, the type Type
must be publicly default-constructible and publicly destructible. For Q_GLOBAL_STATIC_WITH_ARGS(), there must be a public constructor that matches the arguments passed.
It is not possible to use Q_GLOBAL_STATIC with types that have protected or private default constructors or destructors (for Q_GLOBAL_STATIC_WITH_ARGS(), a protected or private constructor matching the arguments). If the type in question has those members as protected, it is possible to overcome the issue by deriving from the type and creating public a constructor and destructor. If the type has them as 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 has them as private, but that defines 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 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_WITH_ARGS(MyType, myGlobal, (42))
Alternatively, if the compiler supports C++11 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 that is necessarily static, at the global scope. It is not possible to place the Q_GLOBAL_STATIC macro inside a function (doing so will result in compilation errors).
More importantly, this macro should be placed in source files, never in headers. Since the resulting object is 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.
Non-recommended uses
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 the 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.