QGlobalStatic Struct
template <typename Holder> struct QGlobalStaticDie Klasse QGlobalStatic wird zur Implementierung eines globalen statischen Objekts verwendet. Mehr...
Kopfzeile: | #include <QGlobalStatic> |
CMake: | find_package(Qt6 REQUIRED COMPONENTS Core) target_link_libraries(mytarget PRIVATE Qt6::Core) |
qmake: | QT += core |
Hinweis: Alle Funktionen in dieser Struktur sind thread-sicher.
Öffentliche Typen
Öffentliche Funktionen
bool | exists() const |
bool | isDestroyed() const |
QGlobalStatic<Holder>::Type * | operator QGlobalStatic<Holder>::Type *() |
QGlobalStatic<Holder>::Type & | operator*() |
QGlobalStatic<Holder>::Type * | operator->() |
Makros
Q_GLOBAL_STATIC(Type, VariableName, ...) |
Detaillierte Beschreibung
Die Klasse QGlobalStatic ist die Front-End-API, die exportiert wird, wenn Q_GLOBAL_STATIC() verwendet wird. In der Dokumentation des Makros wird erläutert, wann es zu verwenden ist und welche Anforderungen es erfüllt.
Normalerweise werden Sie diese Klasse nie direkt verwenden, sondern stattdessen die Makros Q_GLOBAL_STATIC() oder Q_GLOBAL_STATIC_WITH_ARGS(), wie folgt:
Q_GLOBAL_STATIC(MyType, myGlobal)
Das obige Beispiel erzeugt ein Objekt vom Typ QGlobalStatic mit dem Namen myGlobal
. Nach der obigen Deklaration kann das Objekt myGlobal
so verwendet werden, als wäre es ein Zeiger, der garantiert genau einmal initialisiert wird. Zusätzlich zur Verwendung als Zeiger bietet das Objekt zwei Methoden, um den aktuellen Status des Globals zu ermitteln: exists() und isDestroyed().
Siehe auch Q_GLOBAL_STATIC() und Q_GLOBAL_STATIC_WITH_ARGS().
Dokumentation der Mitgliedstypen
[alias]
QGlobalStatic::Type
Dieser Typ entspricht dem Parameter Type
, der an die Makros Q_GLOBAL_STATIC() oder Q_GLOBAL_STATIC_WITH_ARGS() übergeben wird. Er wird in den Rückgabetypen einiger Funktionen verwendet.
Dokumentation der Mitgliedsfunktionen
[noexcept]
bool QGlobalStatic::exists() const
Diese Funktion gibt true
zurück, wenn die Initialisierung des globalen statischen Objekts bereits abgeschlossen ist (d. h. wenn der Konstruktor für den Typ bereits zurückgekehrt ist) und die Zerstörung noch nicht abgeschlossen ist. Beachten Sie insbesondere, dass diese Funktion false
zurückgibt, wenn die Initialisierung noch im Gange ist.
Sobald diese Funktion einmal true zurückgegeben hat, wird sie nie wieder false zurückgeben, bis das globale statische Objekt zerstört wird. Letzteres geschieht beim Beenden des Programms oder wenn das Plugin oder die Bibliothek, die das globale statische Objekt enthält, entladen wird.
Diese Funktion kann an jedem beliebigen Punkt der Programmausführung aufgerufen werden: Sie kann nicht fehlschlagen und keinen Deadlock verursachen. Außerdem führt sie nicht dazu, dass der Inhalt erstellt wird, wenn er noch nicht erstellt wurde.
Diese Funktion ist nützlich, wenn man die Anfangsbedingungen des globalen statischen Objekts bestimmen kann und eine möglicherweise teure Konstruktionsoperation vermeiden möchte.
Im folgenden Codebeispiel wird diese Funktion beispielsweise verwendet, um die Erstellung des globalen statischen Objekts mit der Bezeichnung globalState
zu überbrücken, und gibt einen Standardwert zurück:
Q_GLOBAL_STATIC(MyType, globalState) QString someState() { if (globalState.exists()) return globalState->someState; return QString(); }
Hinweis zur Fadensicherheit: Diese Funktion ist insofern fadensicher, als sie von jedem beliebigen Faden zu jeder Zeit aufgerufen werden kann und immer eine gültige Antwort zurückgibt. Aufgrund der nicht-atomaren Natur der Konstruktion kann diese Funktion jedoch für kurze Zeit nach Abschluss der Konstruktion false zurückgeben.
Hinweis zur Speicherordnung: Diese Funktion bietet keine Garantien für die Speicherordnung. Diese wird stattdessen von den Accessor-Funktionen gewährleistet, die den Zeiger oder den Verweis auf den Inhalt zurückgeben. Wenn Sie die Zugriffsfunktionen umgehen und versuchen, auf einen globalen Zustand zuzugreifen, der durch den Konstruktor festgelegt wurde, stellen Sie sicher, dass Sie die korrekte Speicherordnungssemantik verwenden, die von QAtomicInt oder QAtomicPointer bereitgestellt wird.
Siehe auch isDestroyed().
[noexcept]
bool QGlobalStatic::isDestroyed() const
Diese Funktion gibt true
zurück, wenn die Zerstörung des globalen statischen Objekts bereits abgeschlossen ist (d. h., wenn der Destruktor für den Typ bereits zurückgekehrt ist). Beachten Sie insbesondere, dass diese Funktion false
zurückgibt, wenn die Zerstörung noch im Gange ist.
Sobald diese Funktion einmal true zurückgegeben hat, wird sie nie wieder false zurückgeben, bis entweder das Programm neu gestartet oder das Plugin oder die Bibliothek, die das globale statische Objekt enthält, entladen und neu geladen wird.
Diese Funktion kann an jedem beliebigen Punkt der Programmausführung aufgerufen werden: Sie kann nicht fehlschlagen und keinen Deadlock verursachen. Außerdem wird sie nicht dazu führen, dass der Inhalt erstellt wird, wenn er noch nicht erstellt wurde.
Diese Funktion ist nützlich in Code, der beim Herunterfahren des Programms ausgeführt werden kann, um festzustellen, ob auf den Inhalt noch zugegriffen werden darf oder nicht.
Siehe auch exists().
QGlobalStatic<Holder>::Type *QGlobalStatic::operator QGlobalStatic<Holder>::Type *()
Diese Funktion gibt die Adresse des Inhalts dieser globalen statischen Datei zurück. Wenn der Inhalt noch nicht erstellt wurde, wird er von dieser Funktion thread-sicher erstellt. Wenn der Inhalt bereits zerstört wurde, gibt diese Funktion einen Null-Zeiger zurück.
Diese Funktion kann z.B. verwendet werden, um den Zeiger auf den Inhalt der globalen statischen Datei in einer lokalen Variable zu speichern und so mehrere Aufrufe der Funktion zu vermeiden. Die Implementierung von Q_GLOBAL_STATIC() ist bereits recht effizient, aber in leistungsrelevanten Abschnitten kann es sinnvoll sein, dem Compiler ein wenig zu helfen. Ein Beispiel:
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; }
Siehe auch operator->() und operator*().
QGlobalStatic<Holder>::Type &QGlobalStatic::operator*()
Diese Funktion gibt einen Verweis auf den Inhalt dieser globalen statischen Datei zurück. Wenn der Inhalt noch nicht erstellt wurde, wird er von dieser Funktion thread-sicher erstellt.
Diese Funktion prüft nicht, ob der Inhalt bereits zerstört wurde. Wenn diese Funktion aufgerufen wird, nachdem das Objekt zerstört wurde, gibt sie einen ungültigen Verweis zurück, der nicht verwendet werden darf.
QGlobalStatic<Holder>::Type *QGlobalStatic::operator->()
Diese Funktion gibt die Adresse des Inhalts dieser globalen statischen Datei zurück. Wenn der Inhalt noch nicht erstellt wurde, wird er von dieser Funktion thread-sicher erstellt.
Diese Funktion prüft nicht, ob der Inhalt bereits zerstört wurde und gibt niemals null zurück. Wenn diese Funktion aufgerufen wird, nachdem das Objekt zerstört wurde, gibt sie einen Dangling Pointer zurück, der nicht dereferenziert werden sollte.
Makro-Dokumentation
Q_GLOBAL_STATIC(Type, VariableName, ...)
Erzeugt ein globales und statisches Objekt vom Typ QGlobalStatic, mit dem Namen VariableName und das sich wie ein Zeiger auf Type verhält. Das von Q_GLOBAL_STATIC erzeugte Objekt initialisiert sich bei der ersten Verwendung selbst, was bedeutet, dass es die Ladezeit der Anwendung oder der Bibliothek nicht erhöht. Außerdem wird das Objekt auf allen Plattformen thread-sicher initialisiert.
Seit Qt 6.3 lässt dieses Makro variadische Argumente zu, die zur Initialisierung des Objekts verwendet werden, so dass Q_GLOBAL_STATIC_WITH_ARGS nicht mehr benötigt wird. Bitte beachten Sie, dass die Argumente im Gegensatz zum älteren Makro keinen zusätzlichen Satz von Klammern benötigen.
Die typische Verwendung dieses Makros ist wie folgt, in einem globalen Kontext (d.h. außerhalb von Funktionskörpern):
Q_GLOBAL_STATIC(MyType, myGlobal)
Dieses Makro ist dazu gedacht, globale statische Objekte zu ersetzen, die nicht POD (Plain Old Data, oder in C++11-Begriffen, nicht von einem trivialen Typ) sind, daher der Name. Der folgende C++-Code erzeugt zum Beispiel ein globales statisches Objekt:
static MyType myGlobal;
Im Vergleich zu Q_GLOBAL_STATIC und unter der Annahme, dass MyType
eine Klasse oder Struktur ist, die einen Konstruktor und einen Destruktor hat oder anderweitig nicht POD ist, hat der obige Code die folgenden Nachteile:
- Es erfordert die Initialisierung von
MyType
während des Ladens (d.h. der Standardkonstruktor fürMyType
wird aufgerufen, wenn die Bibliothek oder Anwendung geladen wird); - der Typ wird initialisiert, auch wenn er nie verwendet wird;
- die Reihenfolge der Initialisierung und Zerstörung zwischen verschiedenen Übersetzungseinheiten ist nicht festgelegt, was zu möglichen Verwendungen vor der Initialisierung oder nach der Zerstörung führt;
Das Makro Q_GLOBAL_STATIC löst alle oben genannten Probleme, indem es eine thread-sichere Initialisierung bei der ersten Verwendung garantiert und es dem Benutzer ermöglicht, abzufragen, ob der Typ bereits zerstört wurde, um das Problem der Verwendung nach der Zerstörung zu vermeiden (siehe QGlobalStatic::isDestroyed()).
Konstruktor und Destruktor
Für Q_GLOBAL_STATIC muss der Typ Type
öffentlich standardmäßig konstruierbar und öffentlich zerstörbar sein. Für Q_GLOBAL_STATIC_WITH_ARGS() muss ein öffentlicher Konstruktor vorhanden sein, der zu den übergebenen Argumenten passt.
Es ist nicht möglich, Q_GLOBAL_STATIC mit Typen zu verwenden, die geschützte oder private Standard-Konstruktoren oder -Destruktoren haben (für Q_GLOBAL_STATIC_WITH_ARGS() einen geschützten oder privaten Konstruktor, der zu den Argumenten passt). Wenn der betreffende Typ diese Mitglieder als geschützt hat, ist es möglich, das Problem zu lösen, indem man vom Typ ableitet und einen öffentlichen Konstruktor und Destruktor erstellt. Ist der Typ privat, ist vor der Ableitung eine Friend-Deklaration erforderlich.
Das folgende Beispiel reicht aus, um MyType
auf der Grundlage eines zuvor definierten MyOtherType
zu erstellen, das einen geschützten Standardkonstruktor und/oder einen geschützten Destruktor hat (oder sie als privat hat, aber MyType
als Freund definiert).
class MyType : public MyOtherType { }; Q_GLOBAL_STATIC(MyType, myGlobal)
Es ist kein Body für MyType
erforderlich, da der Destruktor ein implizites Mitglied ist und ebenso der Standardkonstruktor, wenn keine anderen Konstruktoren definiert sind. Für die Verwendung mit Q_GLOBAL_STATIC_WITH_ARGS() ist jedoch ein geeigneter Konstruktorbody erforderlich:
class MyType : public MyOtherType { public: MyType(int i) : MyOtherType(i) {} }; Q_GLOBAL_STATIC_WITH_ARGS(MyType, myGlobal, (42))
Wenn der Compiler C++11 vererbende Konstruktoren unterstützt, könnte man alternativ schreiben:
class MyType : public MyOtherType { public: using MyOtherType::MyOtherType; }; Q_GLOBAL_STATIC_WITH_ARGS(MyType, myGlobal, (42))
Platzierung
Das Makro Q_GLOBAL_STATIC erzeugt einen Typ, der notwendigerweise statisch ist, und zwar im globalen Bereich. Es ist nicht möglich, das Q_GLOBAL_STATIC-Makro innerhalb einer Funktion zu platzieren (dies würde zu Kompilierungsfehlern führen).
Noch wichtiger ist, dass dieses Makro in Quelldateien platziert werden sollte, niemals in Kopfzeilen. Da das resultierende Objekt eine statische Verknüpfung hat, wird das Objekt mehrfach definiert und verursacht keine Verknüpfungsfehler, wenn das Makro in einem Header platziert und von mehreren Quelldateien eingebunden wird. Stattdessen wird jede Übersetzungseinheit auf ein anderes Objekt verweisen, was zu subtilen und schwer zu verfolgenden Fehlern führen kann.
Nicht empfohlene Verwendungen
Beachten Sie, dass das Makro nicht für die Verwendung mit Typen empfohlen wird, die POD sind oder die C++11 constexpr-Konstruktoren haben (trivial konstruierbar und zerstörbar). Für diese Typen wird weiterhin empfohlen, reguläre statische Konstruktoren zu verwenden, egal ob global oder funktionslokal.
Dieses Makro wird funktionieren, aber es wird unnötigen Overhead verursachen.
Wiederholungstendenz, Thread-Sicherheit, Deadlocks und Ausnahmesicherheit bei der Konstruktion
Das Makro Q_GLOBAL_STATIC erzeugt ein Objekt, das sich bei der ersten Verwendung auf eine thread-sichere Weise initialisiert: Wenn mehrere Threads gleichzeitig versuchen, das Objekt zu initialisieren, wird nur ein Thread mit der Initialisierung fortfahren, während alle anderen Threads auf den Abschluss warten.
Wenn der Initialisierungsprozess eine Ausnahme auslöst, gilt die Initialisierung als nicht abgeschlossen und wird erneut versucht, wenn die Kontrolle eine beliebige Verwendung des Objekts erreicht. Wenn es noch Threads gibt, die auf die Initialisierung warten, wird einer von ihnen aufgeweckt, um die Initialisierung zu versuchen.
Das Makro bietet keine Garantie für die Wiederholung der Initialisierung durch denselben Thread. Wenn auf das globale statische Objekt direkt oder indirekt innerhalb des Konstruktors zugegriffen wird, kommt es mit Sicherheit zu einem Deadlock.
Außerdem kann es zu einem Deadlock kommen, wenn zwei Q_GLOBAL_STATIC-Objekte in zwei verschiedenen Threads initialisiert werden und die Initialisierungssequenz des einen auf den anderen zugreift. Aus diesem Grund wird empfohlen, die Konstruktoren für globale statische Objekte einfach zu halten oder andernfalls sicherzustellen, dass es keine gegenseitige Abhängigkeit der Verwendung von globalen statischen Objekten während der Konstruktion gibt.
Zerstörung
Wenn das Objekt während der Lebensdauer des Programms nie benutzt wird, wird der Inhalt des Typs Type nicht erstellt und es gibt keine Exit-Time-Operation, außer bei den Funktionen QGlobalStatic::exists() und QGlobalStatic::isDestroyed().
Wenn das Objekt erstellt wird, wird es zur Beendigungszeit zerstört, ähnlich wie die C-Funktion atexit
. Auf den meisten Systemen wird der Destruktor auch aufgerufen, wenn die Bibliothek oder das Plugin vor dem Beenden aus dem Speicher entladen wird.
Da die Zerstörung beim Beenden des Programms erfolgen soll, ist keine Thread-Sicherheit vorgesehen. Dies gilt auch für den Fall, dass ein Plugin oder eine Bibliothek entladen wird. Da Destruktoren außerdem keine Ausnahmen auslösen sollen, ist auch keine Ausnahmesicherheit vorgesehen.
Allerdings ist Wiederholung erlaubt: Während der Zerstörung ist es möglich, auf das globale statische Objekt zuzugreifen, und der zurückgegebene Zeiger ist derselbe wie vor Beginn der Zerstörung. Nach Abschluss der Zerstörung ist der Zugriff auf das globale statische Objekt nicht mehr zulässig, außer wie in der QGlobalStatic API angegeben.
Siehe auch Q_GLOBAL_STATIC_WITH_ARGS(), Q_APPLICATION_STATIC(), und QGlobalStatic.
© 2025 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.