<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[static initialization order fiasco]]></title><description><![CDATA[<p>Hallo allerseits,</p>
<p>falle ich mit folgendem Code dem <em>static initialization order fiasco</em> zum Opfer?</p>
<p><strong>Baz.h</strong></p>
<pre><code>struct Baz
{
    double v;
};

Baz foo(double input);
Baz bar(double input);
</code></pre>
<p><strong>Baz.cpp</strong></p>
<pre><code>#include &quot;Baz.h&quot;
namespace
{
    const double c1 = 42.0;
    const double c2 = c1 * c1;
    // ... viele weitere Konstanten, welche in den folgenden
    //     Funktionen zur Verfügung stehen sollen
}

Baz foo(double input)
{
    static const double x1 = 123.0;
    static const double x2 = x1 * x1 + 456.0;
    // ... viele weitere Konstanten, die nur innerhalb von foo() benötigt werden

    Baz baz;
    baz.v = input + c1 + c2 + x1 + x2; // unglaublich lange und komplizierte Berechnung, welche
                                       // alle globalen Konstanten c_n und lokalen Konstanten x_n
                                       // enthält
    return baz;
}

Baz bar(double input)
{
    static const double y1 = 123.0;
    static const double y2 = y1 * y1 + 456.0;
    // ... viele weitere Konstanten, die nur innerhalb von bar() benötigt werden

    Baz baz;
    baz.v = input + c1 + c2 + y1 + y2; // unglaublich lange und komplizierte Berechnung, welche
                                       // alle globalen Konstanten c_n und lokalen Konstanten y_n
                                       // enthält
    return baz;
}
</code></pre>
<p><strong>main1.cpp</strong></p>
<pre><code>#include &quot;Baz.h&quot;

int main()
{
	Baz b = foo(999.0);
    return 0;
}
</code></pre>
<p><strong>main2.cpp</strong></p>
<pre><code>#include &quot;Baz.h&quot;

Baz b = foo(999.0);

int main()
{
    return 0;
}
</code></pre>
<p>Ist das Design problematisch? Habt ihr bessere Vorschläge? main1.cpp dürfte ja unkritisch sein; wie siehts mit main2.cpp aus?</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/317609/static-initialization-order-fiasco</link><generator>RSS for Node</generator><lastBuildDate>Tue, 28 Jul 2026 14:20:00 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/317609.rss" rel="self" type="application/rss+xml"/><pubDate>Fri, 14 Jun 2013 11:59:34 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to static initialization order fiasco on Fri, 14 Jun 2013 11:59:34 GMT]]></title><description><![CDATA[<p>Hallo allerseits,</p>
<p>falle ich mit folgendem Code dem <em>static initialization order fiasco</em> zum Opfer?</p>
<p><strong>Baz.h</strong></p>
<pre><code>struct Baz
{
    double v;
};

Baz foo(double input);
Baz bar(double input);
</code></pre>
<p><strong>Baz.cpp</strong></p>
<pre><code>#include &quot;Baz.h&quot;
namespace
{
    const double c1 = 42.0;
    const double c2 = c1 * c1;
    // ... viele weitere Konstanten, welche in den folgenden
    //     Funktionen zur Verfügung stehen sollen
}

Baz foo(double input)
{
    static const double x1 = 123.0;
    static const double x2 = x1 * x1 + 456.0;
    // ... viele weitere Konstanten, die nur innerhalb von foo() benötigt werden

    Baz baz;
    baz.v = input + c1 + c2 + x1 + x2; // unglaublich lange und komplizierte Berechnung, welche
                                       // alle globalen Konstanten c_n und lokalen Konstanten x_n
                                       // enthält
    return baz;
}

Baz bar(double input)
{
    static const double y1 = 123.0;
    static const double y2 = y1 * y1 + 456.0;
    // ... viele weitere Konstanten, die nur innerhalb von bar() benötigt werden

    Baz baz;
    baz.v = input + c1 + c2 + y1 + y2; // unglaublich lange und komplizierte Berechnung, welche
                                       // alle globalen Konstanten c_n und lokalen Konstanten y_n
                                       // enthält
    return baz;
}
</code></pre>
<p><strong>main1.cpp</strong></p>
<pre><code>#include &quot;Baz.h&quot;

int main()
{
	Baz b = foo(999.0);
    return 0;
}
</code></pre>
<p><strong>main2.cpp</strong></p>
<pre><code>#include &quot;Baz.h&quot;

Baz b = foo(999.0);

int main()
{
    return 0;
}
</code></pre>
<p>Ist das Design problematisch? Habt ihr bessere Vorschläge? main1.cpp dürfte ja unkritisch sein; wie siehts mit main2.cpp aus?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2331069</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2331069</guid><dc:creator><![CDATA[Bloops]]></dc:creator><pubDate>Fri, 14 Jun 2013 11:59:34 GMT</pubDate></item><item><title><![CDATA[Reply to static initialization order fiasco on Fri, 14 Jun 2013 12:22:46 GMT]]></title><description><![CDATA[<p>Die Konstanten im anonymen Namespace ( <code>c1</code> , <code>c2</code> , ...) werden alle per <em>constant initialization</em> initialisiert.</p>
<p>N3337 [basic.start.init]/1 schrieb:</p>
<blockquote>
<p>Constant initialization is performed:</p>
<ul>
<li>[...]</li>
<li>if an object with static or thread storage duration is not initialized by a constructor call and if every full-expression that appears in its initializer is a constant expression.</li>
</ul>
</blockquote>
<p>Und daher werden sie vor <code>b</code> in main2.cpp initialisiert, da dieses Objekt dynamisch initialisiert wird.</p>
<blockquote>
<p>Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization. Static initialization shall be performed before any dynamic initialization takes place.</p>
</blockquote>
<p>Damit ist auch main2.cpp richtig.<br />
Mach auch ggf. die Konstanten <code>constexpr</code> .</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2331080</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2331080</guid><dc:creator><![CDATA[Sone]]></dc:creator><pubDate>Fri, 14 Jun 2013 12:22:46 GMT</pubDate></item><item><title><![CDATA[Reply to static initialization order fiasco on Fri, 14 Jun 2013 12:25:13 GMT]]></title><description><![CDATA[<p>Natürlich gilt das nur, solange tatsächlich nur konstante Ausdrücke vorkommen. In deinem Beispiel ist das der Fall. Um das zu erzwingen, qualifiziere die Konstanten nochmal mit <code>constexpr</code> (wenn dein Compiler genügend C++11 unterstützt). Sollte da aber irgendwo = <code>std::sin(5.)</code> stehen, hast du AFAICS ein Problem.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2331085</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2331085</guid><dc:creator><![CDATA[Sone]]></dc:creator><pubDate>Fri, 14 Jun 2013 12:25:13 GMT</pubDate></item><item><title><![CDATA[Reply to static initialization order fiasco on Fri, 14 Jun 2013 12:27:01 GMT]]></title><description><![CDATA[<p>Sone schrieb:</p>
<blockquote>
<p>Sollte da aber irgendwo = <code>std::sin(5.)</code> stehen, hast du AFAICS ein Problem.</p>
</blockquote>
<p>Nicht, wenn sin ein Intrinsic ist.<br />
Wird wohl mit jedem Compiler gehen, aber verlassen kann man sich darauf nicht.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2331086</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2331086</guid><dc:creator><![CDATA[AFAICS]]></dc:creator><pubDate>Fri, 14 Jun 2013 12:27:01 GMT</pubDate></item><item><title><![CDATA[Reply to static initialization order fiasco on Fri, 14 Jun 2013 12:54:23 GMT]]></title><description><![CDATA[<p>Danke für die Anworten. Also wenn ich in den Assembler-Output schaue, dann werden trotz voller Optimierungen nicht sämtliche Konstanten im unnamed namespace <em>constant initialized</em>. Bei manchen steht</p>
<pre><code>c5$initializer$ DQ FLAT:void __cdecl `anonymous namespace'::`dynamic initializer for 'c5''(void)
</code></pre>
<p>und dann später halt die entsprechenden Anweisungen zum berechnen der Werte. Das wundert mich auch sehr, dass hier die <em>constant propagation</em> nicht so funktioniert, wie ich mir das gedacht hatte. VS2012 scheint die double-Konstanten so ca. 3 Ausdrücke weiterzupropagieren, die dann auch alle schön brav zur Compilezeit berechnet werden, aber nachfolgende (immer noch <code>const</code> ) Konstanten werden nicht mehr zur Compilezeit bestimmt. Und das alles, obwohl ich zur Berechnung der Konstanten nur +-*/ verwende (also nix mit Sinus o.ä.).</p>
<p>C++11/constexpr steht mir leider nicht zur Verfügung.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2331099</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2331099</guid><dc:creator><![CDATA[Bloops]]></dc:creator><pubDate>Fri, 14 Jun 2013 12:54:23 GMT</pubDate></item><item><title><![CDATA[Reply to static initialization order fiasco on Mon, 17 Jun 2013 09:17:27 GMT]]></title><description><![CDATA[<p>Hm, ist meine Frage so schwierig, dass keiner sich mehr traut was zu schreiben, oder ist die Antwort so offensichtlich? <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f615.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--confused_face"
      title=":confused:"
      alt="😕"
    /></p>
<p>Wäre für weitere Kommentare sehr dankbar!</p>
<p>Grüße</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2331714</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2331714</guid><dc:creator><![CDATA[Bloops]]></dc:creator><pubDate>Mon, 17 Jun 2013 09:17:27 GMT</pubDate></item><item><title><![CDATA[Reply to static initialization order fiasco on Mon, 17 Jun 2013 09:54:32 GMT]]></title><description><![CDATA[<p>Zeig mal den Code zu den Initialisierungen, die nicht optimiert werden.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2331718</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2331718</guid><dc:creator><![CDATA[SeppJ]]></dc:creator><pubDate>Mon, 17 Jun 2013 09:54:32 GMT</pubDate></item><item><title><![CDATA[Reply to static initialization order fiasco on Mon, 17 Jun 2013 12:03:34 GMT]]></title><description><![CDATA[<p>Gleitkommaliterale sind in C++03 die einzigen konstanten Ausdrücke mit Gleitkommatyp.<br />
Entsprechend ist die Initialisierung von c2/x2/y2 in C++03 dynamisch.<br />
Natürlich könnte ein Compiler die Initialisierung trotzdem statisch durchführen. Traditionell wurde das aber nichtz gemacht, weil es unterschiedliche Implementationen für Gleitkommaarithmetik gibt, und der Compiler diese (ggf. unterschiedlich je nach Zielplattform) implementieren müsste.</p>
<p>In C++11 ist das anders, dort wird aber eben auch nicht ausdrücklich verlangt (allerdings nach Möglichkeit empfohlen), dass das Ergebnis einer Berechnung beim Compilieren mit dem einer Berechnung erst beim Programmablauf exakt übereinstimmen muss.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2331755</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2331755</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Mon, 17 Jun 2013 12:03:34 GMT</pubDate></item><item><title><![CDATA[Reply to static initialization order fiasco on Mon, 17 Jun 2013 16:03:33 GMT]]></title><description><![CDATA[<p>SeppJ schrieb:</p>
<blockquote>
<p>Zeig mal den Code zu den Initialisierungen, die nicht optimiert werden.</p>
</blockquote>
<pre><code>namespace
{
	const double c1 = 123.0;
	const double c2 = 456.0;
	const double c3 = c1 * (c2 - 1.0) / c2;
	const double c4 = ((c1 * c1) - (c3 * c3)) / (c1 * c1);
}

int main()
{
	return c4;
}
</code></pre>
<p><code>c3</code> schafft er noch, <code>c4</code> nicht mehr:</p>
<pre><code>; Listing generated by Microsoft (R) Optimizing Compiler Version 17.00.60315.1 

include listing.inc

INCLUDELIB OLDNAMES

c1	DQ	0405ec00000000000r		; 123
c2	DQ	0407c800000000000r		; 456
CONST	ENDS
PUBLIC	main
PUBLIC	__real@40cd8c8000000000
EXTRN	_fltused:DWORD
c4	DQ	01H DUP ()
_BSS	ENDS
CRT$XCU	SEGMENT
c4$initializer$ DQ FLAT:void __cdecl `anonymous namespace'::`dynamic initializer for 'c4''(void)
CRT$XCU	ENDS
;	COMDAT __real@40cd8c8000000000
CONST	SEGMENT
__real@40cd8c8000000000 DQ 040cd8c8000000000r	; 15129
c3	DQ	0405eaebca1af286cr		; 122.73
_DATA	ENDS
; Function compile flags: /Ogtpy
; File c:\dev\test\test.cpp
;	COMDAT void __cdecl `anonymous namespace'::`dynamic initializer for 'c4''(void)
text$yc	SEGMENT
void __cdecl `anonymous namespace'::`dynamic initializer for 'c4''(void) PROC			; `anonymous namespace'::`dynamic initializer for 'c4'', COMDAT

; 6    : 	const double c4 = ((c1 * c1) - (c3 * c3)) / (c1 * c1);

	movsdx	xmm2, QWORD PTR c3
	movsdx	xmm1, QWORD PTR __real@40cd8c8000000000
	mulsd	xmm2, xmm2
	subsd	xmm1, xmm2
	divsd	xmm1, QWORD PTR __real@40cd8c8000000000
	movsdx	QWORD PTR c4, xmm1
	ret	0
void __cdecl `anonymous namespace'::`dynamic initializer for 'c4''(void) ENDP			; `anonymous namespace'::`dynamic initializer for 'c4''
text$yc	ENDS
; Function compile flags: /Ogtpy
; File c:\dev\test\test.cpp
;	COMDAT main
_TEXT	SEGMENT
main	PROC						; COMDAT

; 11   : 	return c4;

	cvttsd2si eax, QWORD PTR c4

; 12   : }

	ret	0
main	ENDP
_TEXT	ENDS
END
</code></pre>
<p>camper schrieb:</p>
<blockquote>
<p>Gleitkommaliterale sind in C++03 die einzigen konstanten Ausdrücke mit Gleitkommatyp.<br />
Entsprechend ist die Initialisierung von c2/x2/y2 in C++03 dynamisch.<br />
Natürlich könnte ein Compiler die Initialisierung trotzdem statisch durchführen. Traditionell wurde das aber nichtz gemacht, weil es unterschiedliche Implementationen für Gleitkommaarithmetik gibt, und der Compiler diese (ggf. unterschiedlich je nach Zielplattform) implementieren müsste.</p>
<p>In C++11 ist das anders, dort wird aber eben auch nicht ausdrücklich verlangt (allerdings nach Möglichkeit empfohlen), dass das Ergebnis einer Berechnung beim Compilieren mit dem einer Berechnung erst beim Programmablauf exakt übereinstimmen muss.</p>
</blockquote>
<p>Okay, das erklärt einiges. Und was heißt das jetzt bezogen auf meine ursprüngliche Frage? Habe ich also in der Tat bei <strong>main2.cpp</strong> ein Problem? Oder gibts hier sowas wie &quot;beim ersten Aufruf einer Funktion aus einer Übersetzungseinheit sind alle statischen Variablen dieser Übersetzungseinheit initialisiert&quot;? Ich meine, ich hätte im C++-Standard mal irgendwas von Initialisierung statischer Variablen bevor erster ODR-Nutzung einer Funktion in derselben Übersetzungseinheit gelesen. Habe es aber ehrlich gesagt nicht wirklich geblickt.</p>
<p>Was wäre denn ein gutes alternatives Design (C++03), um einer Übersetzungseinheit eine gewisse Menge (ca. 10-20) von Konstanten zur Verfügung zu stellen, welche von mehreren Funktionen dieser Übersetzungseinheit genutzt wird?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2331858</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2331858</guid><dc:creator><![CDATA[Bloops]]></dc:creator><pubDate>Mon, 17 Jun 2013 16:03:33 GMT</pubDate></item><item><title><![CDATA[Reply to static initialization order fiasco on Mon, 17 Jun 2013 16:14:35 GMT]]></title><description><![CDATA[<p>Bloops schrieb:</p>
<blockquote>
<p>Und was heißt das jetzt bezogen auf meine ursprüngliche Frage? Habe ich also in der Tat bei <strong>main2.cpp</strong> ein Problem?</p>
</blockquote>
<p>ja.</p>
<p>Bloops schrieb:</p>
<blockquote>
<p>Oder gibts hier sowas wie &quot;beim ersten Aufruf einer Funktion aus einer Übersetzungseinheit sind alle statischen Variablen dieser Übersetzungseinheit initialisiert&quot;? Ich meine, ich hätte im C++-Standard mal irgendwas von Initialisierung statischer Variablen bevor erster ODR-Nutzung einer Funktion in derselben Übersetzungseinheit gelesen.</p>
</blockquote>
<p>Sofern main bereits betreten wurde, ist das garantiert.</p>
<p>Bloops schrieb:</p>
<blockquote>
<p>Was wäre denn ein gutes alternatives Design (C++03), um einer Übersetzungseinheit eine gewisse Menge (ca. 10-20) von Konstanten zur Verfügung zu stellen, welche von mehreren Funktionen dieser Übersetzungseinheit genutzt wird?</p>
</blockquote>
<p>Spricht etwas dagegen, die Konstanten einfach in einem Header zu definieren (und auf external linkage zu verzichten)?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2331865</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2331865</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Mon, 17 Jun 2013 16:14:35 GMT</pubDate></item><item><title><![CDATA[Reply to static initialization order fiasco on Tue, 18 Jun 2013 09:04:33 GMT]]></title><description><![CDATA[<p>camper schrieb:</p>
<blockquote>
<p>Spricht etwas dagegen, die Konstanten einfach in einem Header zu definieren (und auf external linkage zu verzichten)?</p>
</blockquote>
<p>Meinst du mit <code>static const double ...</code> ? Hab ich dann nicht das gleiche Problem? Dann &quot;sehen&quot; die einzelnen Übesetzungseinheiten doch immer noch verschiedene Konstanten - oder meinst du was anderes?</p>
<p>Die Idee war halt, die (Berechnung der) Konstanten in der Bibliothek komplett wegzukapseln. Ich könnte natürlich die Konstanten auch separat vorberechnen und wirklich nur die Gleitkommaliterale dann in C++ verwenden. Würde mich das dann vor der Initialisierungsproblematik bewahren? Wäre aber halt nicht so elegant.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2332059</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2332059</guid><dc:creator><![CDATA[Bloops]]></dc:creator><pubDate>Tue, 18 Jun 2013 09:04:33 GMT</pubDate></item></channel></rss>