Die endgültige Lösung wird Schritt für Schritt erklärt. Immer kompliziertere Implementierungen erfordern mehrere Dateien und jede Menge Codezeilen. Die wichtigsten Teile des Codes werden nach und nach beleuchtet. Die gesamten Dateien stehen bei TechRepublic als Download zur Verfügung.
Lösung Nr. 1
Zuerst werden Kompilierzeit-Konstanten in Laufzeit-Konstanten umgewandelt. Zunächst werden Properties-Objekte zugelassen. Ein Properties-Objekt beinhaltet Eigenschaften. Man kann eine bestimmte Eigenschaft eines bestimmten Typs abfragen. Eigenschaften können in einer Datei, der Registry usw. gespeichert werden, und der Speicherort ist für den Programmierer klar ersichtlich. Listing C und Listing D zeigen eine Implementierung, bei der jede Eigenschaft in einer eigenen Zeile steht:
Die einfachste Lösung ist die, Konstanten aus einem Properties-Objekt zu initialisieren:
Beim Blick auf Listing E sollten mehrere Aspekte auffallen:
- app_props.h und .cpp ermöglichen den Zugriff auf die Eigenschaften, die aus der Datei props.txt gelesen werden.
- AllUsers.h und .cpp definieren eine einfache Klasse. Über ihren Konstruktor kann auf MAX_USERS zugegriffen werden, eine Konstante, die zur Laufzeit initialisiert wird.
- main.cpp definiert eine globale Variable (s_AllUsers) des Typs AllUsers.
- props.txt enthält einige Eigenschaften (max_users and max_fails).
Bevor man Listing E ausführt, sollte man darauf achten, dass globale Variablen wie s_AllUsers und MAX_USERS vor main() initialisiert werden.
Das Problem wird bei der Ausführung des Beispiels in Listing E klar: Der Konstruktor von AllUsers greift auf die (globale) Konstante MAX_USERS zu. Für den Compiler sind sowohl s_AllUsers als auch MAX_USERS globale Variablen, die zur Laufzeit initialisiert werden. Da die Initialisierungsreihenfolge der globalen Variablen nicht bekannt ist, weiß man auch nicht, welche zuerst initialisiert wird. Wenn s_AllUsers vor MAX_USERS initialisiert wird, betrachtet er MAX_USERS als 0 (statt 1.000) und druckt: „Es können sich max. 0 Anwender einloggen“. Das will man auf keinen Fall erreichen.
Festzustellen ist, dass Probleme nur dann auftreten, wenn globale Variablen globale Konstanten verwenden (in diesem Fall verwendet s_AllUsers MAX_USERS), da man nicht wissen kann, ob man eine Konstante verwendet, bevor diese initialisiert wurde. Wenn eine globale Variable eine lokale Konstante verwendet, entsteht kein Problem, da die lokale Konstante vor ihrer Verwendung initialisiert wird (Listing F). Wenn von nun an von Konstanten gesprochen wird, sind immer globale Konstanten gemeint.
Lösung Nr. 2
Lösung Nr. 1 hat schon darauf hingewiesen: Zwischen Konstanten und von diesen abhängenden Globalen muss unterschieden werden. Die Konstanten werden wie zuvor initialisiert, und die von ihnen abhängigen Globalen werden danach initialisiert. Wie kann man aber wissen, wann die Initialisierung der abhängigen Globalen beginnen soll?
Das ist fast nicht möglich. Befindet man sich jedoch in main(), kann man sicher sein, dass alle Konstanten initialisiert wurden, da diese globale Variablen sind. Aus diesem Grund können die abhängigen globalen Variablen gefahrlos initialisiert werden.
Bei einer abhängigen globalen Variable kann deren Konstruktion verschoben werden, indem alle ihrer Konstruktor-Argumente gepuffert werden. Befindet man sich dann innerhalb von main(), kann sie gefahrlos konstruiert werden. Es muss nur eine Codezeile geändert werden:
So einfach diese Lösung auch klingen mag, es ist recht kompliziert, will man sie in Code übersetzen, über 2.000 Zeilen wurden insgesamt benötigt. Hier einige der Highlights:
- Erstellung einer Template-Klasse (collect_parameters), die alle zum Zeitpunkt der Konstruktion an sie übergebenen Argumente puffert.
- Erstellung einer Template-Klasse (dependent_static< type>), die Collect-Parameter zur Aufnahme der zum Zeitpunkt ihrer Konstruktion übergebenen Argumente verwendet. Beim Aufruf von initialize() wird so die grundlegende Variable erstellt und die gepufferten Argumente werden an sie übergeben.
- Aufruf von all_dependent_statics::initialize_statics() in main() zur Initialisierung aller abhängigen statischen Variablen.
Listing F zeigt, wie die Klassen collect_parameters und dependent_static nach bis zu zwei Parametern suchen. Die endgültige Lösung ermöglicht bis zu 20 Argumente. Mit diesen muss man nur noch die nachstehenden Änderungen in main.cpp vornehmen und neu kompilieren:
Bevor die nächste Lösung besprochen wird, sollte man sich klar sein, dass die Konstanten aus mehreren Richtungen initialisiert werden können: manche aus einer Datei oder mehreren Dateien, aus der Registry – oder von jedem anderen beliebigen Ort. Hierzu implementiert man einfach eine eigene Properties-Klasse.
Neueste Kommentare
Noch keine Kommentare zu Umwandlung von Kompilierzeit-Konstanten zu Laufzeit-Konstanten und umgekehrt
Kommentar hinzufügenVielen Dank für Ihren Kommentar.
Ihr Kommentar wurde gespeichert und wartet auf Moderation.