Folgen von constexpr Konstruktor ohne constexpr Variable
-
Wenn ich eine Klasse
Foo
habe, deren ctorconstexpr
ist, ... soweit ich weiss kann ich dann das Ding ja irgendwo global/static mitconstexpr
instanzieren, und kann sicher sein dass es keine dynamische Initialisierung dafür geben wird. D.h. kein static initialization order fiasco.Soweit richtig?
Was ist aber nun wenn ich eine
Foo
Instanz brauche die nichtconst
sein kann, aber trotzdem sicher sein will dass keine dynamische Initialisierung passiert? Reicht es dazu dass der verwendete Foo Ctorconstexpr
ist?Falls nicht klar ist was ich meine...
struct Foo { constexpr Foo(int i) : j(2 * i) {} int j; }; Foo f{ 21 }; // Darf das hier jemans zu dynamischer Initialisierung führen? Foo* getFoo() { return &f; }
-
Ich hab' jetzt nicht nachgesehen, aber warum sollte
constexpr
Einfluss auf die Initialization Order haben? Vielleicht stehe ich auf diversen Leitungen, aber wie kommst Du darauf?
-
@Swordfish Naja wenns keine dynamische Initialisierung gibt, dann gibt's auch keine Order, und dann kanns auch kein Problem mit der Order geben. Nen?
-
Was ist denn "dynamische Initialisierung"? Ist das Gegentum davon "statische Initialisierung"? Aber, was ist das?
constexpr
hilft Dir nicht zur Umgehung des static initialization order Fiaskos.
-
@hustbaer Der Standard garantiert es tatsaechlich.
Constant initialization is performed if a variable or temporary object with static or thread storage duration is initialized by a constant initializer ([expr.const]) for the entity.
Es ist recht offensichtlich, dass jegliche Eigenschaften eines Initializers nichts mit der constness des zu initialisierenden Objekts zu tun haben.
Du kannst diese Eigenschaft aber testen, es scheint als ob GCC sich nicht an den Standard haelt (es gab aehnliche Bugs wie https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67550)
#include <type_traits> struct Foo { constexpr Foo(int i) : j(2 * i) { if(!std::is_constant_evaluated()) throw; } int j; }; Foo f{ 21 }; // Darf das hier jemans zu dynamischer Initialisierung führen? Foo* getFoo() { return &f; } int main() {}
-
Könnte mich mal jemand aufklären? Entweder stehe ich auf diversen Leitungen oder ich kapiere die "magic" wirklich nicht.
-
@Swordfish
Dynamische Initialisierung:int global = rand(); // Erzeugt einen Library-Konstruktor
Konstante Initialisierung:
int global = 42; // Erzeugt bloss ein paar Bytes im .data Segment
"Statische Initialisierung" ist vielleicht wirklich irreführend.
-
@Swordfish sagte in Folgen von constexpr Konstruktor ohne constexpr Variable:
constexpr hilft Dir nicht zur Umgehung des static initialization order Fiaskos.
Doch, natürlich.
Weil wenn alles schon fertig im .exe/.dll/.so/... File drinnen steht, dann gibt's nix mehr zu initialisierung und daher auch kein Problem mit einer Reihenfolge.
-
@hustbaer sagte in Folgen von constexpr Konstruktor ohne constexpr Variable:
"Statische Initialisierung" ist vielleicht wirklich irreführend.
Warum?
Das Problem der statischen Initialisierung, lässt sich z.B. mit einem Singleton lösen. Das Singleton wird statisch initialisiert, und alle anderen Übersetzungseinheiten können per statischer Methode auf das Singleton zugreifen. Da der erste Zugriff die Initialisierung auslöst, falls noch nicht erfolgt, ist die Reihenfolge der Übersetzungseinheiten vollkommen irrelevant.// foo.h #include <iostream> class Foo { int a_; Foo (); ~Foo(); Foo(Foo&) = delete; Foo(Foo&&) = delete; Foo& operator= (Foo&) = delete; Foo& operator=(Foo&&) = delete; public: static Foo& instance(char const* const name); };
// foo.cc #include <iostream> #include <cstddef> #include <string> #include "foo.h" Foo::~Foo() {} Foo::Foo() : a_(21) { std::cout << "Foo::Foo()\n"; } Foo& Foo::instance(char const*const name) { std::cout << "called from " << name << "\n"; static Foo instance; return instance; } Foo& foo_f = Foo::instance("foo.cc");
// test1.cc #include "foo.h" static Foo& test1_f = Foo::instance("test1.cc");
// main.cc #include <iostream> #include <cstddef> #include "foo.h" static Foo& main_f = Foo::instance("main.cc"); int main () { std::cout << "main.cc\n"; return EXIT_SUCCESS; }
#makefile OFILES_1=test1.o main.o foo.o OFILES_2=test1.o foo.o main.o OFILES_3=main.o test1.o foo.o OFILES_4=main.o foo.o test1.o OFILES_5=foo.o main.o test1.o OFILES_6=foo.o test1.o main.o CCFLAGS=-g -O0 CCC=g++ all: programm1 programm2 programm3 programm4 programm5 programm6 run: ./programm1 ./programm2 ./programm3 ./programm4 ./programm5 ./programm6 programm1: $(OFILES_1) g++ $(OFILES_1) -o programm1 programm2: $(OFILES_2) g++ $(OFILES_2) -o programm2 programm3: $(OFILES_3) g++ $(OFILES_3) -o programm3 programm4: $(OFILES_4) g++ $(OFILES_4) -o programm4 programm5: $(OFILES_5) g++ $(OFILES_5) -o programm5 programm6: $(OFILES_6) g++ $(OFILES_6) -o programm6 .SUFFIXES: .cc .c .h clean: rm -rf *.o programm1 programm2 programm3 programm4 programm5 programm6 .cc.o: $(CCC) $(CCFLAGS) -o $*.o -c $< test1.o: test1.cc foo.h main.o: main.cc foo.h foo.o: foo.h foo.cc
-
@hustbaer sagte in Folgen von constexpr Konstruktor ohne constexpr Variable:
Doch, natürlich.
Na schön. Ich gebe zu mich mit
constexpr
declarations nicht wirklich beschäftigt zu haben. Nur wenn man sich die constraints ansieht ergibt sich dadurch wirklich nur ein sehr eingeschränkter Nutzen wenn es darum geht das Static Initialization Order Fiasco zu umgehen: [decl.constexpr]/9.
-
@Swordfish sagte in Folgen von constexpr Konstruktor ohne constexpr Variable:
Nur wenn man sich die constraints ansieht ergibt sich dadurch wirklich nur ein sehr eingeschränkter Nutzen wenn es darum geht das Static Initialization Order Fiasco zu umgehen: [decl.constexpr]/9.
Ne. Genau darum ging's mir ja in der Frage: Ob es erforderlich ist dass das Objekt selbst
constexpr
gemacht wird, oder ob es reicht dass der verwendete ctorconstexpr
ist. Und wenn ich @Columbo richtig verstanden habe dann reicht es wenn der verwendete ctorconstexpr
ist.D.h. man kann globale/statische SpinLocks und was nicht noch alles schönes (*g*) machen ohne dabei ins Static Initialization Order Fiasco zu rutschen -- vorausgesetzt der ctor dieser schönen Sachen ist
constexpr
. Ob die Objekte selbstconstexpr
sind ist dabei wörscht.
-