2009-10-08 9 views
5

ich die Qt-Codierung Konventionen docs las und kam auf den folgenden Absatz:C++ statische globale nicht-POD: Theorie und Praxis

Alles, was einen Konstruktor hat oder braucht Code auszuführen initialisiert werden kann nicht verwendet werden als globales Objekt im Bibliothekscode, da es nicht definiert ist, wann dieser Konstruktor/Code ausgeführt wird (bei der ersten Verwendung, beim Laden der Bibliothek, vor main() oder gar nicht). Selbst wenn die Ausführungszeit des Initialisierers für gemeinsam genutzte Bibliotheken definiert ist, werden Sie Probleme bekommen, wenn Sie diesen Code in ein Plugin verschieben oder wenn die Bibliothek statisch kompiliert wird.

Ich weiß, was die theory sagt, aber ich verstehe nicht den "überhaupt nicht" -Teil. Manchmal verwende ich globale Nicht-POD-Const-Statik (z. B. QString) und es ist mir nie aufgefallen, dass sie nicht initialisiert werden ... Ist das spezifisch für gemeinsam genutzte Objekte/DLLs? Tritt dies nur bei kaputten Compilern auf?

Was halten Sie von dieser Regel?

+0

Ihr QString wird möglicherweise nicht initialisiert, wenn Sie sie nicht verwenden. Aber wenn Sie sie verwenden, werden sie initialisiert. Auch wenn dies kurz vor dem Gebrauch ist (also kurz bevor das Objekt aufgerufen wird). –

Antwort

8

Der Teil "gar nicht" sagt einfach, dass der C++ - Standard zu diesem Thema nichts sagt. Es weiß nichts über Shared Libraries und sagt daher nichts über die Interaktion bestimmter C++ - Features mit diesen aus.

In der Praxis habe ich globale nicht-POD-statische globale Variablen unter Windows, OSX und vielen Versionen von Linux und anderen Unices sowohl in GUI- als auch in Befehlszeilenprogrammen, als Plugins und als eigenständige Anwendungen verwendet. Mindestens ein Projekt (das statische Nicht-POD-Globals verwendete) hatte Versionen für die vollständige Menge aller Kombinationen davon. Das einzige Problem, das ich je gesehen habe, war, dass einige sehr alte GCC-Versionen Code erzeugten, der die Dtors solcher Objekte in dynamischen Bibliotheken aufruft, wenn die ausführbare Datei gestoppt wurde, nicht wenn die Bibliothek entladen wurde. Natürlich war das fatal (der Bibliothekscode wurde aufgerufen, als die Bibliothek schon weg war), aber das ist fast ein Jahrzehnt her.

Aber das garantiert natürlich noch nichts.

2

Ich glaube nicht, statische Konstruktoren können entfernt werden. Es ist wahrscheinlich eine Verwechslung mit der Tatsache, dass eine statische Bibliothek ist oft nur ein Haufen von Objekten, die Token in der ausführbaren Datei sind , wenn sie sind referenziert. Einige statische Objekte sind so konzipiert, dass sie nicht außerhalb ihres übergeordneten Objekts referenziert werden. Daher wird die Objektdatei nur dann in die ausführbare Datei eingefügt, wenn eine andere Abhängigkeit von ihnen besteht. Dies ist bei einigen Mustern nicht der Fall (unter Verwendung eines statischen Objekts, das sich beispielsweise selbst registriert).

+0

Ich glaube, du verwechselst "statisches Objekt" mit "statischer Bibliothek". – sbi

+1

Mit "statische Objekte" meinte ich "Objekte mit statischer Speicherdauer". BTW, ich habe die Referenz gefunden sagen, dass sie nicht entfernt werden können, wenn ihre Initialisierung oder Destruktor Nebeneffekt hat: 3.7.1/2. – AProgrammer

+0

Ich meinte, dass statische Bibliotheken höchstwahrscheinlich kein Problem sind. Es sind dynamische Bibliotheken, die das Problem sind. – sbi

2

Wenn das statische Objekt in einem Objekt definiert ist, das nicht referenziert wird, kann der Linker das Objekt einschließlich des statischen Initialisierungscodes vollständig beschneiden. Es wird wird regelmäßig für libs (so wird die libc nicht vollständig verknüpft, wenn Teile davon unter gnu, zum Beispiel).

Interessanterweise glaube ich nicht, dass dies für Bibliotheken spezifisch ist. Es kann wahrscheinlich für Objekte selbst im Hauptbau passieren.

2

Ich sehe kein Problem mit globalen Objekten mit Konstruktoren.

Sie sollten nur keine Abhängigkeit von anderen globalen Objekten in ihrem Konstruktor (oder Destruktor) haben.

Aber wenn sie Abhängigkeiten haben, dann muss das abhängige Objekt entweder in der gleichen Kompilierungseinheit sein oder lazily ausgewertet werden, so dass Sie es zwingen können, es zu bewerten, bevor Sie es verwenden.

Der Code im Konstruktor sollte auch nicht davon abhängen, wann (dies hängt mit Abhängigkeiten zusammen, aber nicht ganz gleich) es ausgeführt wird, aber Sie können davon ausgehen, dass es zumindest konstruiert wird eine Methode wird aufgerufen) und C++ garantiert, dass die Reihenfolge der Zerstörung die Umkehrung der Instanziierung ist.

Es ist nicht so schwer, sich an diese Regeln zu halten.

2

C++ definiert nicht die Reihenfolge, die statische Initialisierer für Objekte in verschiedenen Kompilierungseinheiten ausführen (die Reihenfolge ist innerhalb einer Kompilierungseinheit gut definiert).

Betrachten Sie die Situation, in der Sie 2 statische Objekte A und B in verschiedenen Kompilierungseinheiten definiert haben. Nehmen wir an, dass Objekt B bei der Initialisierung tatsächlich Objekt A verwendet.

In diesem Szenario ist es möglich, dass B zuerst initialisiert wird und einen Aufruf für ein nicht initialisiertes A-Objekt ausführt. Dies kann eine Sache sein, die mit "überhaupt nicht" gemeint ist - ein Objekt wird verwendet, wenn es keine Gelegenheit hatte, es selbst zuerst zu initialisieren (selbst wenn es später initialisiert wird).

Ich nehme an, dass dynamisches Verknüpfen Komplexitäten hinzufügen kann, von denen ich nicht gedacht habe, dass ein Objekt nie initialisiert wird. So oder so, die Quintessenz ist, dass statische initializatino genügend potenzielle Probleme eingeführt, die es wo möglich vermieden und sehr sorgfältig behandelt werden sollte, wo Sie es verwenden müssen.

Verwandte Themen