QGlobalStatic Struct

template <typename Holder> struct QGlobalStatic

Die 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. Siehe die Dokumentation des Makros für eine Diskussion über seine Anforderungen und wann es zu verwenden ist.

Normalerweise werden Sie diese Klasse nie direkt verwenden, sondern stattdessen das Makro Q_GLOBAL_STATIC(), wie folgt:

Q_GLOBAL_STATIC(MyType, myGlobal)

Das obige Beispiel erzeugt ein Objekt vom Typ QGlobalStatic namens myGlobal. Nach der obigen Deklaration kann das Objekt myGlobal so verwendet werden, als wäre es ein Zeiger auf ein Objekt vom Typ MyType, das 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()
{
    if (globalState::isDestroyed())
        return QString();
    MyType *state = globalState;
    if (state->condition)
        return state->value;
    else
        return state->worth;
}

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 eine ungültige Referenz zurück, die nicht verwendet werden darf.

Siehe auch exists() und isDestroyed().

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.

Siehe auch exists() und isDestroyed().

Makro-Dokumentation

Q_GLOBAL_STATIC(Type, variableName, ...)

Erzeugt ein globales und statisches Objekt vom Typ QGlobalStatic mit dem Namen variableName. Es verhält sich wie ein Zeiger auf Type. 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 verlängert. 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. nicht innerhalb eines Funktions- oder Klassenkörpers):

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 letzteres die folgenden Nachteile:

  • Es erfordert die Initialisierung von myGlobal während des Ladens (d.h. der Standardkonstruktor für MyType wird aufgerufen, wenn die Bibliothek oder Anwendung geladen wird);
  • das Objekt wird auch dann initialisiert, wenn es nie benutzt 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 durch die Konstruktoren oder Destruktoren anderer globaler Variablen führt.

Das Makro Q_GLOBAL_STATIC löst all diese Probleme, indem es eine thread-sichere Initialisierung bei der ersten Verwendung garantiert und dem Benutzer erlaubt, 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, wenn nur ein Typ und ein Variablenname angegeben sind, muss Type öffentlich Standard-konstruierbar und öffentlich zerstörbar sein. Andernfalls muss Type einen öffentlichen Konstruktor haben, der die verbleibenden Argumente des Makros annimmt. Für Q_GLOBAL_STATIC_WITH_ARGS() muss es einen öffentlichen Konstruktor geben, der das dritte Argument des Makros als Liste von Parametern annimmt.

Es ist nicht möglich, Q_GLOBAL_STATIC mit einem Type zu verwenden, dessen entsprechender Konstruktor oder Destruktor geschützt oder privat ist. Wenn der betreffende Typ diese Mitglieder als geschützt deklariert, ist es möglich, das Problem zu umgehen, indem man von dem Typ ableitet und einen öffentlichen Konstruktor und Destruktor erstellt. Wenn der Typ sie als privat deklariert, ist vor der Ableitung eine Friend-Deklaration erforderlich.

Das folgende Beispiel genügt, 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 deklariert, aber auch MyType als Freund deklariert).

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 Argumenten nach Type und variableName oder mit Q_GLOBAL_STATIC_WITH_ARGS() ist jedoch ein geeigneter Konstruktorkörper erforderlich:

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

Alternativ (seit C++11 vererbende Konstruktoren eingeführt hat) könnte man auch 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 und eine Variable dieses Typs, die notwendigerweise statisch ist, im globalen Bereich. Es ist nicht möglich, das Q_GLOBAL_STATIC-Makro innerhalb einer Funktion oder des Körpers einer Klasse 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 statisch verknüpft ist, wird das Objekt, wenn das Makro in einem Header platziert und von mehreren Quelldateien eingebunden wird, mehrfach definiert und verursacht keine Verknüpfungsfehler. Stattdessen wird jede Übersetzungseinheit auf ein anderes Objekt verweisen, was zu subtilen und schwer zu verfolgenden Fehlern führen kann.

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 von seinem eigenen Konstruktor aus 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 Wiederverknüpfung 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.