Funktion nur einmal aufrufen
-
rean schrieb:
Jetzt bräuchten wir die kompetente Meinung eines Standard-Spezialisten
Hab schon ein wenig gestöbert aber konnte nix Definitives finden.Naja, der Standard sagt, dass (Klassen)globale static Variablen beim Programmstart initialisiert werden. Ich überlege allerdings, ob es Probleme mit Race Conditions geben kann, wenn in einer anderen Übersetzungseinheit
foo
zur Initialisierung einer anderen globelen Variable herangezogen wird.
-
Ausserdem sagt der Standard nichts über Threading aus. Das wird im Standard fast komplett ausgeblendet.
Simon
-
@Tachyon,
Nein, der Standard ist etwas komplizierter bei non-local objects. Die Objekte werden spätestens dann initialisiert, wenn die erste Funktion aus der entsprechenden TU aufgerufen wird, vorher werden sie zero-initialised. Das macht ja auchstatic public
Membervariablen von Klassen so gefährlich.Bei der Lösung von pumuckl heisst dies, dass spätestens bei der ersten Verwendung der Klasse, also erstellen eines Objektes oder aufrufen einer Funktion, die init-Funktion aufgerufen wird.
Bei der Lösung von Registrierter Troll, werden keine non-local Objekte benötigt, dadurch besteht das Problem nicht. Dafür ist seine Lösung nicht Threadsicher.
Bei der Lösung von rean, wird die init-Funktion garantiert gleich beim Programmstart aufgerufen, weil der zero-initiliser vom
struct
der Defaultkonstruktor ist.Da beim Aufstart eines Programmes immer nur ein Thread ist, ist die Lösung von rean, meiner Meinung nach, auch Thread-sicher.
Bei Der Lösung von pumuckl bin ich mir nicht ganz sicher. Aber eine Initialisierung einer Variable dürfte eigentlich nur einmal passieren. Da der Standard aber nichts über Threads sagt, bin ich mir da schlicht und einfach nicht sicher.
Grüssli
-
Dravere schrieb:
Die Objekte werden spätestens dann initialisiert, wenn die erste Funktion aus der entsprechenden TU aufgerufen wird, vorher werden sie zero-initialised.
Das möchte ich doch stark bezweifeln. Was du da sagst bedeutet im Grunde, dass für diese Objekte erst ein (eventuell nichtmal vorhandener) Default-Ctor aufgerufen würde, später gefolgt von einem zweiten Ctor Aufruf für das selbe Objekt, was völlig wider die allgemeine Auffassung von Objektlebenszeiten in C++ geht. Wahrscheinlicher ist, dass für die entsprechenden Objekte im Datensegment Speicher bereitgehalten wird und sie dann zum gegebenen Zeitpunkt an der entsprechenden Stelle konstruiert werden.
-
Also ich habe das so verstanden, ich zitiere mal den Ausschnitt aus dem Standard.
C++ 2003, 3.6.2 Initialization of non-local objects, Abschnitt 1 schrieb:
Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization
takes place. Zero-initialization and initialization with a constant expression are collectively called static
initialization; all other initialization is dynamic initialization. Objects of POD types (3.9) with static stor-
age duration initialized with constant expressions (5.19) shall be initialized before any dynamic initial-
ization takes place. Objects with static storage duration defined in namespace scope in the same translation
unit and dynamically initialized shall be initialized in the order in which their definition appears in the
translation unit. [Note: 8.5.1 describes the order in which aggregate members are initialized. The initial-
ization of local static objects is described in 6.7. ]Grüssli
-
Das nenn ich mal missglückte Formulierung im Standard. Für mich liest sich das wie folgt:
Statische Objekte werden genau einmal initialisiert, und zwar in der folgenden Reihenfolge
- zero-initialisierte Objekte (das ist nicht default-initialisiert, siehe 8.5)
- PODs, die mit einem konstanten Ausdruck initialisiert werden
- dynamisch initialisierte Objekte, d.h. Objekte, die mit Funktionsergebnissen, nichtkonstanten anderen statischen Variablen oder nichttrivialen Konstruktoren initialisiert werden. letzteres schließt Klassen ein, die zwar einen trivialen (compilergenerierten) default-Ctor haben, die aber Member oder Basisklassen mit nichttrivialen Konstruktoren haben.
-
@pumuckl:
Genau.
Wirklich gut verlassen kann man sich nur auf 1) und 2), also zero-init und const-init.Und alles was dynamisch passiert, kann AFAIK verzögert werden, bis die erste Funktion einer TU aufgerufen wird.
Dahier ist auch die Aussage von Dravere
Bei der Lösung von rean, wird die init-Funktion garantiert gleich beim Programmstart aufgerufen, weil der zero-initiliser vom struct der Defaultkonstruktor ist.
nicht richtig, da dies ja nicht "static initialization" ist.
-
@pumuckl,
8.5 Abschnitt 5
"To zero-initialize an object of type T means:"
...
"— if T is a non-POD class type (clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);"Also ich weiss echt nicht. Ich fand das schon immer sehr verwunderlich, aber wenn da explizit steht, dass vor jeglicher Initialisierung eine zero-Intialisierung folgt. Wie soll man diesen Satz denn sonst verstehen?
hustbaer schrieb:
Bei der Lösung von rean, wird die init-Funktion garantiert gleich beim Programmstart aufgerufen, weil der zero-initiliser vom struct der Defaultkonstruktor ist.
nicht richtig, da dies ja nicht "static initialization" ist.
Wieso nicht? Das Objekt
rfi
iststatic
in der Klasse.Grüssli
-
Wieso nicht? Das Objekt rfi ist static in der Klasse.
Das "static" in "static initialization" und das "static" in "static storage duration" sind zwei gänzlich unterschiedliche "static" - eins hat mit dem anderen nichts zu tun.
Ich kann im Moment leider nicht lustig rumzitieren (sitz grad nicht vor meinem eigenen PC, wo ich den Standard zu Hand hätte)... wenn ich dran denke schlag ich nachher die relevanten Stellen nach und poste sie.
-
Wird die Sachlage dadurch geändert dass man ein const vor das ganze stellt?
class foo { //.... static const struct run_foo_init{ run_foo_init(){ foo::foo_init(); } } rfi; }; //... const foo::run_foo_init foo::rfi;
-
Verzweifelnder schrieb:
Hallo,
ich habe eine Klasse geschreiben (von der es auch mehr als nur ein Objekt geben kann / keine Singleton-Klasse). Damit diese Klasse richtig funktioniert muss einmal am Anfang vom Programm eine Funktion aufgerufen werden (aber nur EINMAL im Programm, nicht einmal pro Objekt). Muss ich das nun wirklich an den Anfang der main-function schreiben (gefällt mir überhaupt nicht, weil die Funktion ja mit der Klasse in Verbindung stehen sollte)??Wozu braucht man sowas?
-
hustbaer schrieb:
Das "static" in "static initialization" und das "static" in "static storage duration" sind zwei gänzlich unterschiedliche "static" - eins hat mit dem anderen nichts zu tun.
Das ist schon klar, nur ...
Ach, ich warte einfach bis du geantwortet hast. Würde mich freuen, wenn du mich da erhellen könntest. Habe mich erst vor kurzem damit etwas genauer beschäftigt. Dachte eigentlich, ich hätte es nun endlich raus.Grüssli
-
Dravere schrieb:
8.5 Abschnitt 5
"To zero-initialize an object of type T means:"
...
"— if T is a non-POD class type (clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);"Du schummelst. Dein "..." enthält etwas was du nicht weglassen darfst, wenn du die Bedeutung nicht total verdrehen willst.
To zero-initialize an object of type T means:
— if T is a scalar type (3.9), the object is set to the value of 0 (zero) converted to T;
— if T is a non-union class type, each nonstatic data member and each base-class subobject is zeroinitialized;
— if T is a union type, the object’s first named data member89) is zero-initialized;
— if T is an array type, each element is zero-initialized;
— if T is a reference type, no initialization is performed.
To default-initialize an object of type T means: <------------------ *** WICHTIG ***
— if T is a non-POD class type (clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
— if T is an array type, each element is default-initialized;
— otherwise, the object is zero-initialized.Steht ganz klar hier: der Aufruf eines ctors ist nicht zero-initialization. (Ich auch logisch) Default-initialization ist ein Begriff, der bezüglich der Reihenfolge bzw. des Zeitpunktes wann initialisiert wird überhaupt keine Bedeutung hat, da Default-initialization eben zero-initialization oder dynamic-initialization sein kann.
Der Rest steht dann in 3.6.2: Initialization of non-local objects.
Zusammengefasst (und grob vereinfacht): zuerst wird immer alles (alle non-local statics) "zero-initialized". Dann kommen PODs die direkt mit (compile-time-) konstanten Ausdrücken initialisiert werden.
(BTW: ein POD kann keinen ctor haben, da ein POD ein aggregate ist, und ein aggregate eben keinen ctor haben kann.)Was den Zeitpunkt angeht zu dem Objekte initialisiert werden auf die das nicht zutrifft (keine PODs, oder mit nicht-konstanten Ausdrücken initialisiert)...
3.6.2 Absatz 3:It is implementation-defined whether or not the dynamic initialization (8.5, 9.4, 12.1, 12.6.1) of an object of
namespace scope is done before the first statement of main. If the initialization is deferred to some point
in time after the first statement of main, it shall occur before the first use of any function or object defined
in the same translation unit as the object to be initialized.