Topic: Proposal: Solving the static init order problem:
Author: fmatthew5876@gmail.com
Date: Tue, 12 Nov 2013 18:01:02 -0800 (PST)
Raw View
------=_Part_2430_15794409.1384308062184
Content-Type: text/plain; charset=ISO-8859-1
We all know that the static initialization order across translation units
is undefined. This makes effectively using globals with non-trivial
constructors and destructors impossible because we cannot control their
startup and shutdown order. The strongest use case for a real global is a
logger object. Indeed we already have 2 of these in the standard library,
that is cout and cerr.
One solution proposed is to just a lazy initialized singleton pattern like
the Meyers singleton. This has a few problems:
- Lazy initialization may not be appropriate for the object if it's
used all the time and meant to be ready for use from the first line of
main().
- There are still no guarantees about destruction order. This is
critical for something like a logging system. The author of modern C++
design (Andrei Alexandrescu) tried very hard to find a solution to this
problem and none of them were very satisfactory.
Another proposed solution is the so called Nifty Counter which is now
used by IO streams.
http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Nifty_Counter
This technique solves the initialization order problem, however it
comes with an unnecessary runtime cost. Every translation unit gets a
static constructor. While having such a runtime technique for controlling
initialization order is interesting and potentially useful in its
own right, there is no reason the compiler and linker shouldn't be able
to handle this.
One major C++ project (LLVM) outright bans the iostream header because of
this runtime cost:
http://llvm.org/docs/CodingStandards.html#include-iostream-is-forbidden
Here is a new potential solution which would require additional logic in
the compiler and the linker with zero runtime overhead.
The reason why static initialization across translation units is unordered
is because the translation units themselves are effectively unordered. The
proposal aims to solve the static initialization order problem by allowing
the programmer to specify a global ordering on the translation units and
libraries that make up an application.
The way this would be done is to tag an extern symbol. Right now I am going
to use the explicit keyword but any such syntax could be invented. For the
examples below, I am only going to write .cc files with declarations in
them. Normally users of course would use header files for declarations.
These .cc files should be considered the entire translation unit after all
header files are included. Also assume a class type Foo with non-trivial
constructors and destructors is also defined in each translation unit.
Here is how it would look:
//a.cc
//a.o now depends on whatever translation unit or library contains the
bglobal symbol
explicit extern Foo bglobal;
//We construct a global object which is initialized via copy constructor
using bglobal.
//Normally this is undefined behavior, but because bglobal is declared with
explicit extern, we
//are guaranteed that bglobal has been constructed before aglobal and will
be destructed after aglobal.
Foo aglobal(bglobal);
//b.cc
//Since bglobal is actually defined in this translation unit, this is just
a normal forward declaration.
explicit extern Foo bglobal;
Foo bglobal;
Implementation:
Here is a rough sketch of how this could be implemented on a unix system.
I'm not an expert so there may be holes in this plan.
For each translation unit, the compiler can collect all of the explicit
extern declarations that are used once and write them out to special ELF
section in the .o file called .symdeps. This .symdeps section will contain
all of the mangled symbol names that this object file depends on.
Now the linker, when combining all of these objects, can check the .symdeps
sections of each object file and search for the symbol in the other object
files to form a dependency graph. If a symbol in the .symdeps section of
one object file is not found in another, its the same thing as normal
undefined reference linker error.
After the graph is constructed, the linker sorts them using a simple
topological sort. If a cycle is detected, a linker error results. The
static initialization of each translation unit in the final application or
library will be guaranteed occur in sorted order.
Other examples:
Like I stated earlier, cycles will cause linker errors. This is an example
of a cycle:
//a.cc
//a.o now depends on the translation unit that defines b
explicit extern Foo b;
Foo a;
//b.cc
//b.o now depends on the translation unit defines a
explicit extern Foo a;
Foo b;
The static initialization order of different translation units are still
distinct, they will not be merged together. Consider this example:
//c.cc
Foo a;
explicit extern Foo b;
Foo c;
What is the initialization order here? The answer is b, a, and then c. The
explicit extern creates a translation unit dependency and thus enforces
that whomever defines b gets initialized first. Then a and c get
initialized because of the already existing rules for static initialization
within single translation units.
What if a symbol is declared but never used?
//a.cc
explicit extern Foo b;
In this case, the compiler must omit the .symdeps entry for this symbol.
This avoids the linker overhead of sorting when its not required and more
importantly prevents false cycles.
What if a translation unit depends on more than 1 symbol?
//a.cc
explicit extern Foo a;
explicit extern Foo b;
Foo c;
void foo() {
doSomethingWith(a, b);
}
In this case, both a and be are guaranteed to be initialized before c, but
in undefined order.
Do you think a feature like this would be considered by the standards
committee? Perhaps if there was a proof of concept implementation?
I'd like to ask a very BIG FAVOR of everyone here. Please 1000 times, lets
keep this discussion to the technical merits/faults and feasibility of this
idea. The subject of globals being never use evil vs necessary evil and
dependency injection has been done over a million times. Please I beg of
you don't derail this thread into another one of those discussions.
Thanks!
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
------=_Part_2430_15794409.1384308062184
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">We all know that the static initialization order across tr=
anslation units is undefined. This makes effectively using globals with non=
-trivial constructors and destructors impossible because we cannot con=
trol their startup and shutdown order. The strongest use case for a re=
al global is a logger object. Indeed we already have 2 of these in the stan=
dard library, that is cout and cerr.<br><br>One solution proposed is to jus=
t a lazy initialized singleton pattern like the Meyers singleton. This=
has a few problems: <br>- Lazy initialization may not be appropriate =
for the object if it's used all the time and meant to be ready for use=
from the first line of main(). <br>- There are still no guarantees ab=
out destruction order. This is critical for something like a logging s=
ystem. The author of modern C++ design (Andrei Alexandrescu) tried ver=
y hard to find a solution to this problem and none of them were very s=
atisfactory. <br><br>Another proposed solution is the so called Nifty =
Counter which is now used by IO streams. <br><a href=3D"http://en=
..wikibooks.org/wiki/More_C%2B%2B_Idioms/Nifty_Counter" target=3D"_blank" st=
yle=3D"cursor: pointer;">http://en.wikibooks.org/wiki/<wbr>More_C%2B%2B_Idi=
oms/Nifty_<wbr>Counter</a> <br><br>This technique solves the initializ=
ation order problem, however it comes with an unnecessary runtime cost=
.. Every translation unit gets a static constructor. While having such a run=
time technique for controlling initialization order is interesting and pote=
ntially useful in its own right, there is no reason the compiler and l=
inker shouldn't be able to handle this. <br><br><div>One major C+=
+ project (LLVM) outright bans the iostream header because of this run=
time cost: <br><a href=3D"http://llvm.org/docs/CodingStandards.html#in=
clude-iostream-is-forbidden" target=3D"_blank" style=3D"cursor: pointer;">h=
ttp://llvm.org/docs/<wbr>CodingStandards.html#include-<wbr>iostream-is-forb=
idden</a> <br><br>Here is a new potential solution which would require=
additional logic in the compiler and the linker with zero runtime overhead=
..</div><div><br></div><div>The reason why static initialization across tran=
slation units is unordered is because the translation units themselves are =
effectively unordered. The proposal aims to solve the static initialization=
order problem by allowing the programmer to specify a global ordering on t=
he translation units and libraries that make up an application.</div><div><=
br></div><div>The way this would be done is to tag an extern symbol. Right =
now I am going to use the explicit keyword but any such syntax could be inv=
ented. For the examples below, I am only going to write .cc files with decl=
arations in them. Normally users of course would use header files for decla=
rations. These .cc files should be considered the entire translation unit a=
fter all header files are included. Also assume a class type Foo with non-t=
rivial constructors and destructors is also defined in each translation uni=
t.</div><div><br></div><div>Here is how it would look:</div><div>//a.cc</di=
v><div><br></div><div>//a.o now depends on whatever translation unit or lib=
rary contains the bglobal symbol</div><div>explicit extern Foo bglobal;</di=
v><div><br></div><div>//We construct a global object which is initialized v=
ia copy constructor using bglobal.</div><div>//Normally this is undefined b=
ehavior, but because bglobal is declared with explicit extern, we </di=
v><div>//are guaranteed that bglobal has been constructed before aglobal an=
d will be destructed after aglobal.</div><div>Foo aglobal(bglobal);</div><d=
iv><br></div><div><br></div><div>//b.cc</div><div><br></div><div>//Since bg=
lobal is actually defined in this translation unit, this is just a normal f=
orward declaration.</div><div>explicit extern Foo bglobal;</div><div><br></=
div><div>Foo bglobal;</div><div><br></div><div><br></div><div>Implementatio=
n:</div><div>Here is a rough sketch of how this could be implemented on a u=
nix system. I'm not an expert so there may be holes in this plan.</div><div=
><br></div><div>For each translation unit, the compiler can collect all of =
the explicit extern declarations that are used once and write them out to s=
pecial ELF section in the .o file called .symdeps. This .symdeps section wi=
ll contain all of the mangled symbol names that this object file depends on=
..</div><div><br></div><div>Now the linker, when combining all of these obje=
cts, can check the .symdeps sections of each object file and search for the=
symbol in the other object files to form a dependency graph. If a symbol i=
n the .symdeps section of one object file is not found in another, its the =
same thing as normal undefined reference linker error.</div><div><br></div>=
<div>After the graph is constructed, the linker sorts them using a simple t=
opological sort. If a cycle is detected, a linker error results. The static=
initialization of each translation unit in the final application or librar=
y will be guaranteed occur in sorted order.</div><div><br></div><div>Other =
examples:</div><div>Like I stated earlier, cycles will cause linker errors.=
This is an example of a cycle:</div><div><br></div><div>//a.cc</div><div>/=
/a.o now depends on the translation unit that defines b</div><div>explicit =
extern Foo b;</div><div><br></div><div>Foo a;</div><div><br></div><div>//b.=
cc</div><div>//b.o now depends on the translation unit defines a</div><div>=
explicit extern Foo a;</div><div><br></div><div>Foo b;</div><div><br></div>=
<div>The static initialization order of different translation units are sti=
ll distinct, they will not be merged together. Consider this example:</div>=
<div>//c.cc</div><div><br></div><div>Foo a;</div><div>explicit extern Foo b=
;</div><div>Foo c;</div><div><br></div><div>What is the initialization orde=
r here? The answer is b, a, and then c. The explicit extern creates a trans=
lation unit dependency and thus enforces that whomever defines b gets initi=
alized first. Then a and c get initialized because of the already existing =
rules for static initialization within single translation units.</div><div>=
<br></div><div>What if a symbol is declared but never used?</div><div>//a.c=
c</div><div>explicit extern Foo b;</div><div><br></div><div>In this case, t=
he compiler must omit the .symdeps entry for this symbol. This avoids the l=
inker overhead of sorting when its not required and more importantly preven=
ts false cycles.</div><div><br></div><div>What if a translation unit depend=
s on more than 1 symbol?</div><div>//a.cc</div><div>explicit extern Foo a;<=
/div><div>explicit extern Foo b;</div><div><br></div><div>Foo c;</div><div>=
void foo() {<br> doSomethingWith(a, b);</div><div>}</div><div><br></d=
iv><div>In this case, both a and be are guaranteed to be initialized before=
c, but in undefined order. </div><div><br></div><div>Do you think a f=
eature like this would be considered by the standards committee? Perhaps if=
there was a proof of concept implementation?</div><div><br></div><div>I'd =
like to ask a very BIG FAVOR of everyone here. Please 1000 times, lets keep=
this discussion to the technical merits/faults and feasibility of this ide=
a. The subject of globals being never use evil vs necessary evil and depend=
ency injection has been done over a million times. Please I beg of you don'=
t derail this thread into another one of those discussions.</div><div><br><=
/div><div>Thanks!</div><div><br></div></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_2430_15794409.1384308062184--
.
Author: Richard Smith <richard@metafoo.co.uk>
Date: Tue, 12 Nov 2013 18:13:43 -0800
Raw View
--089e011834d8b5266404eb058393
Content-Type: text/plain; charset=ISO-8859-1
On Tue, Nov 12, 2013 at 6:01 PM, <fmatthew5876@gmail.com> wrote:
> We all know that the static initialization order across translation units
> is undefined. This makes effectively using globals with non-trivial
> constructors and destructors impossible because we cannot control their
> startup and shutdown order. The strongest use case for a real global is a
> logger object. Indeed we already have 2 of these in the standard library,
> that is cout and cerr.
>
> One solution proposed is to just a lazy initialized singleton pattern like
> the Meyers singleton. This has a few problems:
> - Lazy initialization may not be appropriate for the object if it's
> used all the time and meant to be ready for use from the first line of
> main().
> - There are still no guarantees about destruction order. This is
> critical for something like a logging system. The author of modern C++
> design (Andrei Alexandrescu) tried very hard to find a solution to this
> problem and none of them were very satisfactory.
>
> Another proposed solution is the so called Nifty Counter which is now
> used by IO streams.
> http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Nifty_Counter
>
> This technique solves the initialization order problem, however it
> comes with an unnecessary runtime cost. Every translation unit gets a
> static constructor. While having such a runtime technique for controlling
> initialization order is interesting and potentially useful in its
> own right, there is no reason the compiler and linker shouldn't be able
> to handle this.
>
> One major C++ project (LLVM) outright bans the iostream header because of
> this runtime cost:
> http://llvm.org/docs/CodingStandards.html#include-iostream-is-forbidden
>
> Here is a new potential solution which would require additional logic in
> the compiler and the linker with zero runtime overhead.
>
> The reason why static initialization across translation units is unordered
> is because the translation units themselves are effectively unordered. The
> proposal aims to solve the static initialization order problem by allowing
> the programmer to specify a global ordering on the translation units and
> libraries that make up an application.
>
> The way this would be done is to tag an extern symbol. Right now I am
> going to use the explicit keyword but any such syntax could be invented.
> For the examples below, I am only going to write .cc files with
> declarations in them. Normally users of course would use header files for
> declarations. These .cc files should be considered the entire translation
> unit after all header files are included. Also assume a class type Foo with
> non-trivial constructors and destructors is also defined in each
> translation unit.
>
> Here is how it would look:
> //a.cc
>
> //a.o now depends on whatever translation unit or library contains the
> bglobal symbol
> explicit extern Foo bglobal;
>
> //We construct a global object which is initialized via copy constructor
> using bglobal.
> //Normally this is undefined behavior, but because bglobal is declared
> with explicit extern, we
> //are guaranteed that bglobal has been constructed before aglobal and will
> be destructed after aglobal.
> Foo aglobal(bglobal);
>
>
> //b.cc
>
> //Since bglobal is actually defined in this translation unit, this is just
> a normal forward declaration.
> explicit extern Foo bglobal;
>
> Foo bglobal;
>
>
> Implementation:
> Here is a rough sketch of how this could be implemented on a unix system.
> I'm not an expert so there may be holes in this plan.
>
> For each translation unit, the compiler can collect all of the explicit
> extern declarations that are used once and write them out to special ELF
> section in the .o file called .symdeps. This .symdeps section will contain
> all of the mangled symbol names that this object file depends on.
>
> Now the linker, when combining all of these objects, can check the
> .symdeps sections of each object file and search for the symbol in the
> other object files to form a dependency graph. If a symbol in the .symdeps
> section of one object file is not found in another, its the same thing as
> normal undefined reference linker error.
>
> After the graph is constructed, the linker sorts them using a simple
> topological sort. If a cycle is detected, a linker error results. The
> static initialization of each translation unit in the final application or
> library will be guaranteed occur in sorted order.
>
> Other examples:
> Like I stated earlier, cycles will cause linker errors. This is an example
> of a cycle:
>
> //a.cc
> //a.o now depends on the translation unit that defines b
> explicit extern Foo b;
>
> Foo a;
>
> //b.cc
> //b.o now depends on the translation unit defines a
> explicit extern Foo a;
>
> Foo b;
>
> The static initialization order of different translation units are still
> distinct, they will not be merged together. Consider this example:
> //c.cc
>
> Foo a;
> explicit extern Foo b;
> Foo c;
>
> What is the initialization order here? The answer is b, a, and then c. The
> explicit extern creates a translation unit dependency and thus enforces
> that whomever defines b gets initialized first. Then a and c get
> initialized because of the already existing rules for static initialization
> within single translation units.
>
> What if a symbol is declared but never used?
> //a.cc
> explicit extern Foo b;
>
> In this case, the compiler must omit the .symdeps entry for this symbol.
> This avoids the linker overhead of sorting when its not required and more
> importantly prevents false cycles.
>
> What if a translation unit depends on more than 1 symbol?
> //a.cc
> explicit extern Foo a;
> explicit extern Foo b;
>
> Foo c;
> void foo() {
> doSomethingWith(a, b);
> }
>
> In this case, both a and be are guaranteed to be initialized before c, but
> in undefined order.
>
> Do you think a feature like this would be considered by the standards
> committee?
>
Not as it stands, no. Mutually-referencing source files are overwhelmingly
common, so you will reject a lot of real code because it contains "cycles".
I would expect that no non-trivial program would link under this model.
Having said that, the modules proposal gives us a guarantee of no cycles
across modules, and it has been the intent from the start that this acyclic
graph would be used to order static initialization of module globals.
(However, each module will typically comprise more than one of today's
header files, so cycles *within* a module would still be problematic. These
could be solved by fiat: the current ideas for describing a module include
a list of the files within the module, and that list provides us with an
order.)
> Perhaps if there was a proof of concept implementation?
>
> I'd like to ask a very BIG FAVOR of everyone here. Please 1000 times, lets
> keep this discussion to the technical merits/faults and feasibility of this
> idea. The subject of globals being never use evil vs necessary evil and
> dependency injection has been done over a million times. Please I beg of
> you don't derail this thread into another one of those discussions.
>
> Thanks!
>
> --
>
> ---
> You received this message because you are subscribed to the Google Groups
> "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> Visit this group at
> http://groups.google.com/a/isocpp.org/group/std-proposals/.
>
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
--089e011834d8b5266404eb058393
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Tue, Nov 12, 2013 at 6:01 PM, <span dir=3D"ltr"><<a=
href=3D"mailto:fmatthew5876@gmail.com" target=3D"_blank">fmatthew5876@gmai=
l.com</a>></span> wrote:<br><div class=3D"gmail_extra"><div class=3D"gma=
il_quote">
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><div dir=3D"ltr">We all know that the static=
initialization order across translation units is undefined. This makes eff=
ectively using globals with non-trivial constructors and destructors imposs=
ible because we=A0cannot control their startup and shutdown order.=A0The st=
rongest use case for a real global is a logger object. Indeed we already ha=
ve 2 of these in the standard library, that is cout and cerr.<br>
<br>One solution proposed is to just a lazy initialized singleton pattern=
=A0like the Meyers singleton. This has a few problems:=A0<br>- Lazy initial=
ization may not be appropriate for the object if it's used=A0all the ti=
me and meant to be ready for use from the first line of main().=A0<br>
- There are still no guarantees about destruction order. This is critical=
=A0for something like a logging system. The author of modern C++ design (An=
drei Alexandrescu)=A0tried very hard to find a solution to this problem and=
none of them=A0were very satisfactory.=A0<br>
<br>Another proposed solution is the so called Nifty Counter which is now u=
sed=A0by IO streams.=A0<br><a href=3D"http://en.wikibooks.org/wiki/More_C%2=
B%2B_Idioms/Nifty_Counter" target=3D"_blank">http://en.wikibooks.org/wiki/<=
u></u>More_C%2B%2B_Idioms/Nifty_<u></u>Counter</a>=A0<br>
<br>This technique solves the initialization order problem, however it come=
s=A0with an unnecessary runtime cost. Every translation unit gets a static =
constructor. While having such a runtime technique for controlling initiali=
zation order is interesting and potentially useful in its own=A0right, ther=
e is no reason the compiler and linker shouldn't be able to=A0handle th=
is.=A0<br>
<br><div>One major C++ project (LLVM) outright bans the iostream header bec=
ause=A0of this runtime cost:=A0<br><a href=3D"http://llvm.org/docs/CodingSt=
andards.html#include-iostream-is-forbidden" target=3D"_blank">http://llvm.o=
rg/docs/<u></u>CodingStandards.html#include-<u></u>iostream-is-forbidden</a=
>=A0<br>
<br>Here is a new potential solution which would require additional logic i=
n the compiler and the linker with zero runtime overhead.</div><div><br></d=
iv><div>The reason why static initialization across translation units is un=
ordered is because the translation units themselves are effectively unorder=
ed. The proposal aims to solve the static initialization order problem by a=
llowing the programmer to specify a global ordering on the translation unit=
s and libraries that make up an application.</div>
<div><br></div><div>The way this would be done is to tag an extern symbol. =
Right now I am going to use the explicit keyword but any such syntax could =
be invented. For the examples below, I am only going to write .cc files wit=
h declarations in them. Normally users of course would use header files for=
declarations. These .cc files should be considered the entire translation =
unit after all header files are included. Also assume a class type Foo with=
non-trivial constructors and destructors is also defined in each translati=
on unit.</div>
<div><br></div><div>Here is how it would look:</div><div>//a.cc</div><div><=
br></div><div>//a.o now depends on whatever translation unit or library con=
tains the bglobal symbol</div><div>explicit extern Foo bglobal;</div><div>
<br></div><div>//We construct a global object which is initialized via copy=
constructor using bglobal.</div><div>//Normally this is undefined behavior=
, but because bglobal is declared with explicit extern, we=A0</div><div>//a=
re guaranteed that bglobal has been constructed before aglobal and will be =
destructed after aglobal.</div>
<div>Foo aglobal(bglobal);</div><div><br></div><div><br></div><div>//b.cc</=
div><div><br></div><div>//Since bglobal is actually defined in this transla=
tion unit, this is just a normal forward declaration.</div><div>explicit ex=
tern Foo bglobal;</div>
<div><br></div><div>Foo bglobal;</div><div><br></div><div><br></div><div>Im=
plementation:</div><div>Here is a rough sketch of how this could be impleme=
nted on a unix system. I'm not an expert so there may be holes in this =
plan.</div>
<div><br></div><div>For each translation unit, the compiler can collect all=
of the explicit extern declarations that are used once and write them out =
to special ELF section in the .o file called .symdeps. This .symdeps sectio=
n will contain all of the mangled symbol names that this object file depend=
s on.</div>
<div><br></div><div>Now the linker, when combining all of these objects, ca=
n check the .symdeps sections of each object file and search for the symbol=
in the other object files to form a dependency graph. If a symbol in the .=
symdeps section of one object file is not found in another, its the same th=
ing as normal undefined reference linker error.</div>
<div><br></div><div>After the graph is constructed, the linker sorts them u=
sing a simple topological sort. If a cycle is detected, a linker error resu=
lts. The static initialization of each translation unit in the final applic=
ation or library will be guaranteed occur in sorted order.</div>
<div><br></div><div>Other examples:</div><div>Like I stated earlier, cycles=
will cause linker errors. This is an example of a cycle:</div><div><br></d=
iv><div>//a.cc</div><div>//a.o now depends on the translation unit that def=
ines b</div>
<div>explicit extern Foo b;</div><div><br></div><div>Foo a;</div><div><br><=
/div><div>//b.cc</div><div>//b.o now depends on the translation unit define=
s a</div><div>explicit extern Foo a;</div><div><br></div><div>Foo b;</div>
<div><br></div><div>The static initialization order of different translatio=
n units are still distinct, they will not be merged together. Consider this=
example:</div><div>//c.cc</div><div><br></div><div>Foo a;</div><div>explic=
it extern Foo b;</div>
<div>Foo c;</div><div><br></div><div>What is the initialization order here?=
The answer is b, a, and then c. The explicit extern creates a translation =
unit dependency and thus enforces that whomever defines b gets initialized =
first. Then a and c get initialized because of the already existing rules f=
or static initialization within single translation units.</div>
<div><br></div><div>What if a symbol is declared but never used?</div><div>=
//a.cc</div><div>explicit extern Foo b;</div><div><br></div><div>In this ca=
se, the compiler must omit the .symdeps entry for this symbol. This avoids =
the linker overhead of sorting when its not required and more importantly p=
revents false cycles.</div>
<div><br></div><div>What if a translation unit depends on more than 1 symbo=
l?</div><div>//a.cc</div><div>explicit extern Foo a;</div><div>explicit ext=
ern Foo b;</div><div><br></div><div>Foo c;</div><div>void foo() {<br>=A0 do=
SomethingWith(a, b);</div>
<div>}</div><div><br></div><div>In this case, both a and be are guaranteed =
to be initialized before c, but in undefined order.=A0</div><div><br></div>=
<div>Do you think a feature like this would be considered by the standards =
committee?</div>
</div></blockquote><div><br></div><div>Not as it stands, no. Mutually-refer=
encing source files are overwhelmingly common, so you will reject a lot of =
real code because it contains "cycles". I would expect that no no=
n-trivial program would link under this model.</div>
<div><br></div><div>Having said that, the modules proposal gives us a guara=
ntee of no cycles across modules, and it has been the intent from the start=
that this acyclic graph would be used to order static initialization of mo=
dule globals. (However, each module will typically comprise more than one o=
f today's header files, so cycles *within* a module would still be prob=
lematic. These could be solved by fiat: the current ideas for describing a =
module include a list of the files within the module, and that list provide=
s us with an order.)</div>
<div>=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;=
border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>Perhaps =
if there was a proof of concept implementation?</div><div><br></div><div>I&=
#39;d like to ask a very BIG FAVOR of everyone here. Please 1000 times, let=
s keep this discussion to the technical merits/faults and feasibility of th=
is idea. The subject of globals being never use evil vs necessary evil and =
dependency injection has been done over a million times. Please I beg of yo=
u don't derail this thread into another one of those discussions.</div>
<div><br></div><div>Thanks!</div><span class=3D"HOEnZb"><font color=3D"#888=
888"><div><br></div></font></span></div><span class=3D"HOEnZb"><font color=
=3D"#888888">
<p></p>
-- <br>
=A0<br>
--- <br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals%2Bunsubscribe@isocpp.org" target=3D=
"_blank">std-proposals+unsubscribe@isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br>
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/" target=3D"_blank">http://groups.google.com/a/isocpp.org/gro=
up/std-proposals/</a>.<br>
</font></span></blockquote></div><br></div></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
--089e011834d8b5266404eb058393--
.
Author: David Krauss <potswa@gmail.com>
Date: Wed, 13 Nov 2013 10:45:01 +0800
Raw View
On 11/13/13 10:01 AM, fmatthew5876@gmail.com wrote:
> We all know that the static initialization order across translation units
> is undefined. This makes effectively using globals with non-trivial
> constructors and destructors impossible because we cannot control their
> startup and shutdown order. The strongest use case for a real global is a
> logger object. Indeed we already have 2 of these in the standard library,
> that is cout and cerr.
>
> One solution proposed is to just a lazy initialized singleton pattern like
> the Meyers singleton. This has a few problems:
> - Lazy initialization may not be appropriate for the object if it's
> used all the time and meant to be ready for use from the first line of
> main().
> - There are still no guarantees about destruction order. This is
> critical for something like a logging system. The author of modern C++
> design (Andrei Alexandrescu) tried very hard to find a solution to this
> problem and none of them were very satisfactory.
Even static local objects are guaranteed to be destroyed in the reverse
order of construction.
> Another proposed solution is the so called Nifty Counter which is now
> used by IO streams.
> http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Nifty_Counter
It was used in early implementations of iostream but isn't specified by
the standard, and implementations may choose not to use it.
> While having such a runtime technique for controlling
> initialization order is interesting and potentially useful in its
> own right, there is no reason the compiler and linker shouldn't be able
> to handle this.
Most implementations do have some platform-specific means.
> One major C++ project (LLVM) outright bans the iostream header because of
> this runtime cost:
> http://llvm.org/docs/CodingStandards.html#include-iostream-is-forbidden
Runtime cost isn't cited there, and the construct doesn't have
significant runtime cost. Its problem is robustness against the case
that some TU does not include the header before calling an extern
function that requires the streams to be initialized.
The standard strictly only requires that the standard streams are
initialized once static initialization in a TU including <iostream> (not
<iosfwd> or <ios>) has gotten past that inclusion. But, best practice is
otherwise to avoid <iostream> as it's heavyweight. This conflict makes
it easy to write code that could access uninitialized streams, so I
think that the mechanism is out of favor in real-world implementations.
Anyway, Clang is in the minority. It also rejects other standard
facilities in favor of, for instance, custom containers. It essentially
comes down to the cost of maintaining a custom standard library.
> Here is a new potential solution which would require additional logic in
> the compiler and the linker with zero runtime overhead.
It sounds like you want to build a partial weak ordering among TUs by
using the "explicit extern" syntax to define a relationship where the TU
defining the explicit extern object must be initialized before all TUs
only declaring it.
If the relationships fail to be an ordering, then the program would have
a circular dependency so it should be ill-formed.
I don't see why that can't work portably and with full backward
compatibility within existing binary formats. Instead of a single
initialization function with no parameters, a shared library would
export a table of TU records containing its sets of explicit extern
dependencies and definitions, and a TU initialization function. The
futuristic C++ loader would check all libraries for such records and
order the TUs accordingly, and otherwise fall back on the old-fashioned
static initialization for libraries with no dependency list.
> I'd like to ask a very BIG FAVOR of everyone here. Please 1000 times, lets
> keep this discussion to the technical merits/faults and feasibility of this
> idea. The subject of globals being never use evil vs necessary evil and
> dependency injection has been done over a million times. Please I beg of
> you don't derail this thread into another one of those discussions.
The next step sounds like a prototype extension to GCC or Clang. Good luck!
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
.
Author: fmatthew5876@gmail.com
Date: Tue, 12 Nov 2013 19:10:10 -0800 (PST)
Raw View
------=_Part_13_738914.1384312210928
Content-Type: text/plain; charset=ISO-8859-1
On Tuesday, November 12, 2013 9:13:43 PM UTC-5, Richard Smith wrote:
>
> Not as it stands, no. Mutually-referencing source files are overwhelmingly
> common, so you will reject a lot of real code because it contains "cycles".
> I would expect that no non-trivial program would link under this model.
>
Source files can mutually reference each other as much as they like as long
as they don't have explicit extern relationships with one another. Since
this explicit extern syntax is current invalid, no currently compiling code
will break. A cycle only occurs in this case:
//a.cc
//Now depends on b.o
explicit extern Foo b;
Foo b(a);
//b.cc
//Now depends on a.o
explicit extern Foo a;
Foo a(b);
>
> Having said that, the modules proposal gives us a guarantee of no cycles
> across modules, and it has been the intent from the start that this acyclic
> graph would be used to order static initialization of module globals.
> (However, each module will typically comprise more than one of today's
> header files, so cycles *within* a module would still be problematic. These
> could be solved by fiat: the current ideas for describing a module include
> a list of the files within the module, and that list provides us with an
> order.)
>
Modules sound great, but I don't know what they are or how long they will
take to be implemented if ever. I'd like a more immediate solution to this
problem.
>
>
>> Perhaps if there was a proof of concept implementation?
>>
>> I'd like to ask a very BIG FAVOR of everyone here. Please 1000 times,
>> lets keep this discussion to the technical merits/faults and feasibility of
>> this idea. The subject of globals being never use evil vs necessary evil
>> and dependency injection has been done over a million times. Please I beg
>> of you don't derail this thread into another one of those discussions.
>>
>> Thanks!
>>
>> --
>>
>> ---
>> You received this message because you are subscribed to the Google Groups
>> "ISO C++ Standard - Future Proposals" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to std-proposal...@isocpp.org <javascript:>.
>> To post to this group, send email to std-pr...@isocpp.org <javascript:>.
>> Visit this group at
>> http://groups.google.com/a/isocpp.org/group/std-proposals/.
>>
>
>
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
------=_Part_13_738914.1384312210928
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><br>On Tuesday, November 12, 2013 9:13:43 PM UTC-5, Ri=
chard Smith wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;marg=
in-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"=
ltr"><div><div class=3D"gmail_quote"><div>Not as it stands, no. Mutually-re=
ferencing source files are overwhelmingly common, so you will reject a lot =
of real code because it contains "cycles". I would expect that no non-trivi=
al program would link under this model.</div></div></div></div></blockquote=
><div><br></div><div>Source files can mutually reference each other as much=
as they like as long as they don't have explicit extern relationships with=
one another. Since this explicit extern syntax is current invalid, no curr=
ently compiling code will break. A cycle only occurs in this case:</div><di=
v>//a.cc</div><div>//Now depends on b.o</div><div>explicit extern Foo b;</d=
iv><div><br></div><div>Foo b(a);</div><div> </div><div>//b.cc</div><di=
v>//Now depends on a.o</div><div>explicit extern Foo a;</div><div><br></div=
><div>Foo a(b);</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;m=
argin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=
=3D"ltr"><div><div class=3D"gmail_quote">
<div><br></div><div>Having said that, the modules proposal gives us a guara=
ntee of no cycles across modules, and it has been the intent from the start=
that this acyclic graph would be used to order static initialization of mo=
dule globals. (However, each module will typically comprise more than one o=
f today's header files, so cycles *within* a module would still be problema=
tic. These could be solved by fiat: the current ideas for describing a modu=
le include a list of the files within the module, and that list provides us=
with an order.)</div></div></div></div></blockquote><div><br></div><div>Mo=
dules sound great, but I don't know what they are or how long they will tak=
e to be implemented if ever. I'd like a more immediate solution to this pro=
blem.</div><div> </div><blockquote class=3D"gmail_quote" style=3D"marg=
in: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><d=
iv dir=3D"ltr"><div><div class=3D"gmail_quote">
<div> </div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8=
ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>Perha=
ps if there was a proof of concept implementation?</div><div><br></div><div=
>I'd like to ask a very BIG FAVOR of everyone here. Please 1000 times, lets=
keep this discussion to the technical merits/faults and feasibility of thi=
s idea. The subject of globals being never use evil vs necessary evil and d=
ependency injection has been done over a million times. Please I beg of you=
don't derail this thread into another one of those discussions.</div>
<div><br></div><div>Thanks!</div><span><font color=3D"#888888"><div><br></d=
iv></font></span></div><span><font color=3D"#888888">
<p></p>
-- <br>
<br>
--- <br>
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"javascript:" target=3D"_blank" gdf-obfuscated-mailto=3D"=
zWG7zpTNpvQJ">std-proposal...@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"javascript:" target=3D"_bla=
nk" gdf-obfuscated-mailto=3D"zWG7zpTNpvQJ">std-pr...@isocpp.org</a>.<br>
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/" target=3D"_blank">http://groups.google.com/a/<wbr>isocpp.or=
g/group/std-<wbr>proposals/</a>.<br>
</font></span></blockquote></div><br></div></div>
</blockquote></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_13_738914.1384312210928--
.
Author: fmatthew5876@gmail.com
Date: Tue, 12 Nov 2013 19:46:16 -0800 (PST)
Raw View
------=_Part_2749_12191095.1384314376493
Content-Type: text/plain; charset=ISO-8859-1
On Tuesday, November 12, 2013 9:45:01 PM UTC-5, David Krauss wrote:
>
> On 11/13/13 10:01 AM, fmatth...@gmail.com <javascript:> wrote:
> > We all know that the static initialization order across translation
> units
> > is undefined. This makes effectively using globals with non-trivial
> > constructors and destructors impossible because we cannot control their
> > startup and shutdown order. The strongest use case for a real global is
> a
> > logger object. Indeed we already have 2 of these in the standard
> library,
> > that is cout and cerr.
> >
> > One solution proposed is to just a lazy initialized singleton pattern
> like
> > the Meyers singleton. This has a few problems:
> > - Lazy initialization may not be appropriate for the object if it's
> > used all the time and meant to be ready for use from the first line of
> > main().
> > - There are still no guarantees about destruction order. This is
> > critical for something like a logging system. The author of modern C++
> > design (Andrei Alexandrescu) tried very hard to find a solution to this
> > problem and none of them were very satisfactory.
>
> Even static local objects are guaranteed to be destroyed in the reverse
> order of construction.
>
That still doesn't help. Consider this horrible scenario.
Logger& log() {
static Logger logger;
return logger;
}
class Foo {
Foo() { }
~Foo() { log() << "Destroying foo" << std::endl; }
};
Foo f;
int main() {
log() << "MAIN CALLED" std::endl;
}
The order of events is this:
Foo is constructed
main is entered
static Logger is constructed
main returns
static Logger is destructed
Foo destructor is called, tries to log to an invalid object.
One workaround here though is to be sure to call log from the Foo
constructor.
>
> > Another proposed solution is the so called Nifty Counter which is now
> > used by IO streams.
> > http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Nifty_Counter
>
> It was used in early implementations of iostream but isn't specified by
> the standard, and implementations may choose not to use it.
>
> > While having such a runtime technique for controlling
> > initialization order is interesting and potentially useful in its
> > own right, there is no reason the compiler and linker shouldn't be able
> > to handle this.
>
> Most implementations do have some platform-specific means.
>
Yes, but they are platform specific. Gcc has this thing where you can give
an integer priority score to each object, but that's not scalable at all
between different projects.
>
> > One major C++ project (LLVM) outright bans the iostream header because
> of
> > this runtime cost:
> > http://llvm.org/docs/CodingStandards.html#include-iostream-is-forbidden
>
> Runtime cost isn't cited there, and the construct doesn't have
> significant runtime cost.
They mention 2 performance issues with static constructors here:
http://llvm.org/docs/CodingStandards.html#static-constructor
> Its problem is robustness against the case
> that some TU does not include the header before calling an extern
> function that requires the streams to be initialized.
>
> The standard strictly only requires that the standard streams are
> initialized once static initialization in a TU including <iostream> (not
> <iosfwd> or <ios>) has gotten past that inclusion. But, best practice is
> otherwise to avoid <iostream> as it's heavyweight. This conflict makes
> it easy to write code that could access uninitialized streams, so I
> think that the mechanism is out of favor in real-world implementations.
>
Thats interesting, I think we still have a problem then:
//foo.cc
void useC();
Foo::Foo() {
useC();
}
//c.cc
explicit extern Bar c;
Bar c;
void useC() {
c.doSomething();
}
//a.cc
explicit extern Bar c;
Foo a; //Ok, c is ordered before a
//b.cc
Foo b; //ERROR no ordering between b and c, and its not obvious that there
should be!
There would need to be a policy of always including an explicit extern
declaration for any globals the functions you place in your header might
use. This sounds like something that could easily cause a lot of nasty bugs.
> Anyway, Clang is in the minority. It also rejects other standard
> facilities in favor of, for instance, custom containers. It essentially
> comes down to the cost of maintaining a custom standard library.
>
> > Here is a new potential solution which would require additional logic in
> > the compiler and the linker with zero runtime overhead.
>
> It sounds like you want to build a partial weak ordering among TUs by
> using the "explicit extern" syntax to define a relationship where the TU
> defining the explicit extern object must be initialized before all TUs
> only declaring it.
>
Thats exactly right.
>
> If the relationships fail to be an ordering, then the program would have
> a circular dependency so it should be ill-formed.
>
> Yes, cycles cause a link error
> I don't see why that can't work portably and with full backward
> compatibility within existing binary formats. Instead of a single
> initialization function with no parameters, a shared library would
> export a table of TU records containing its sets of explicit extern
> dependencies and definitions, and a TU initialization function. The
> futuristic C++ loader would check all libraries for such records and
> order the TUs accordingly, and otherwise fall back on the old-fashioned
> static initialization for libraries with no dependency list.
>
> > I'd like to ask a very BIG FAVOR of everyone here. Please 1000 times,
> lets
> > keep this discussion to the technical merits/faults and feasibility of
> this
> > idea. The subject of globals being never use evil vs necessary evil and
> > dependency injection has been done over a million times. Please I beg of
> > you don't derail this thread into another one of those discussions.
>
> The next step sounds like a prototype extension to GCC or Clang. Good
> luck!
>
I would be happy to do this. I want to gauge interest first. It doesn't
make sense to spend a lot of time implementing a prototype version of this
feature just to have the proposal shot down. Still, the function issue is
rather scary. I'm surprised this doesn't show up more often with iostream.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
------=_Part_2749_12191095.1384314376493
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><br>On Tuesday, November 12, 2013 9:45:01 PM UTC-5, Da=
vid Krauss wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margi=
n-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On 11/13/13 1=
0:01 AM, <a href=3D"javascript:" target=3D"_blank" gdf-obfuscated-mailto=3D=
"KQJdYMFdAiEJ">fmatth...@gmail.com</a> wrote:
<br>> We all know that the static initialization order across translatio=
n units
<br>> is undefined. This makes effectively using globals with non-trivia=
l
<br>> constructors and destructors impossible because we cannot control =
their
<br>> startup and shutdown order. The strongest use case for a real glob=
al is a
<br>> logger object. Indeed we already have 2 of these in the standard l=
ibrary,
<br>> that is cout and cerr.
<br>>
<br>> One solution proposed is to just a lazy initialized singleton patt=
ern like
<br>> the Meyers singleton. This has a few problems:
<br>> - Lazy initialization may not be appropriate for the object if it'=
s
<br>> used all the time and meant to be ready for use from the first lin=
e of
<br>> main().
<br>> - There are still no guarantees about destruction order. This is
<br>> critical for something like a logging system. The author of modern=
C++
<br>> design (Andrei Alexandrescu) tried very hard to find a solution to=
this
<br>> problem and none of them were very satisfactory.
<br>
<br>Even static local objects are guaranteed to be destroyed in the reverse=
=20
<br>order of construction.
<br></blockquote><div><br></div><div>That still doesn't help. Consider this=
horrible scenario.</div><div><br></div><div>Logger& log() {</div><div>=
static Logger logger;</div><div> return logger;<br>}</div><div=
><br></div><div>class Foo {<br> Foo() { } </div><div> =
; ~Foo() { log() << "Destroying foo" << std::endl; } </div=
><div>};</div><div><br></div><div>Foo f;</div><div><br></div><div>int main(=
) {<br> log() << "MAIN CALLED" std::endl;</div><div>}</div><div=
><br></div><div>The order of events is this:</div><div>Foo is constructed</=
div><div>main is entered</div><div>static Logger is constructed</div><div>m=
ain returns</div><div>static Logger is destructed</div><div>Foo destructor =
is called, tries to log to an invalid object.</div><div><br></div><div>One =
workaround here though is to be sure to call log from the Foo constructor.<=
/div><div><br></div><div> </div><blockquote class=3D"gmail_quote" styl=
e=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left:=
1ex;">
<br>> Another proposed solution is the so called Nifty Counter which is =
now
<br>> used by IO streams.
<br>> <a href=3D"http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Nifty_=
Counter" target=3D"_blank">http://en.wikibooks.org/wiki/<wbr>More_C%2B%2B_I=
dioms/Nifty_<wbr>Counter</a>
<br>
<br>It was used in early implementations of iostream but isn't specified by=
=20
<br>the standard, and implementations may choose not to use it.
<br>
<br>> While having such a runtime technique for controlling
<br>> initialization order is interesting and potentially useful in its
<br>> own right, there is no reason the compiler and linker shouldn't be=
able
<br>> to handle this.
<br>
<br>Most implementations do have some platform-specific means.
<br></blockquote><div>Yes, but they are platform specific. Gcc has this thi=
ng where you can give an integer priority score to each object, but that's =
not scalable at all between different projects. </div><blockquote clas=
s=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #c=
cc solid;padding-left: 1ex;">
<br>> One major C++ project (LLVM) outright bans the iostream header bec=
ause of
<br>> this runtime cost:
<br>> <a href=3D"http://llvm.org/docs/CodingStandards.html#include-iostr=
eam-is-forbidden" target=3D"_blank">http://llvm.org/docs/<wbr>CodingStandar=
ds.html#include-<wbr>iostream-is-forbidden</a>
<br>
<br>Runtime cost isn't cited there, and the construct doesn't have=20
<br>significant runtime cost. </blockquote><div><br></div><div>They mention=
2 performance issues with static constructors here:</div><div><a href=3D"h=
ttp://llvm.org/docs/CodingStandards.html#static-constructor">http://llvm.or=
g/docs/CodingStandards.html#static-constructor</a><br></div><div><br></div>=
<div> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margi=
n-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">Its problem i=
s robustness against the case=20
<br>that some TU does not include the header before calling an extern=20
<br>function that requires the streams to be initialized.
<br>
<br>The standard strictly only requires that the standard streams are=20
<br>initialized once static initialization in a TU including <iostream&g=
t; (not=20
<br><iosfwd> or <ios>) has gotten past that inclusion. But, bes=
t practice is=20
<br>otherwise to avoid <iostream> as it's heavyweight. This conflict =
makes=20
<br>it easy to write code that could access uninitialized streams, so I=20
<br>think that the mechanism is out of favor in real-world implementations.
<br></blockquote><div><br></div><div>Thats interesting, I think we still ha=
ve a problem then:</div><div>//foo.cc</div><div>void useC();</div><div><br>=
</div><div>Foo::Foo() {<br> useC();</div><div>}</div><div><br></div><=
div><div>//c.cc</div><div><br></div><div>explicit extern Bar c;</div><div><=
br></div><div>Bar c;</div><div><br></div><div>void useC() {<br> c.doS=
omething(); </div><div>}</div></div><div><br></div><div>//a.cc</div><d=
iv><br></div><div>explicit extern Bar c;<br></div><div>Foo a; //Ok, c is or=
dered before a</div><div><br></div><div>//b.cc</div><div><br></div><div>Foo=
b; //ERROR no ordering between b and c, and its not obvious that there sho=
uld be!</div><div><br></div><div><br></div><div>There would need to be a po=
licy of always including an explicit extern declaration for any globals the=
functions you place in your header might use. This sounds like something t=
hat could easily cause a lot of nasty bugs.</div><div><br></div><blockquote=
class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1=
px #ccc solid;padding-left: 1ex;">
<br>Anyway, Clang is in the minority. It also rejects other standard=20
<br>facilities in favor of, for instance, custom containers. It essentially=
=20
<br>comes down to the cost of maintaining a custom standard library.
<br>
<br>> Here is a new potential solution which would require additional lo=
gic in
<br>> the compiler and the linker with zero runtime overhead.
<br>
<br>It sounds like you want to build a partial weak ordering among TUs by=
=20
<br>using the "explicit extern" syntax to define a relationship where the T=
U=20
<br>defining the explicit extern object must be initialized before all TUs=
=20
<br>only declaring it.
<br></blockquote><div> </div><div>Thats exactly right.</div><div> =
;</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.=
8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<br>If the relationships fail to be an ordering, then the program would hav=
e=20
<br>a circular dependency so it should be ill-formed.
<br>
<br></blockquote><div>Yes, cycles cause a link error</div><div> </div>=
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bor=
der-left: 1px #ccc solid;padding-left: 1ex;">I don't see why that can't wor=
k portably and with full backward=20
<br>compatibility within existing binary formats. Instead of a single=20
<br>initialization function with no parameters, a shared library would=20
<br>export a table of TU records containing its sets of explicit extern=20
<br>dependencies and definitions, and a TU initialization function. The=20
<br>futuristic C++ loader would check all libraries for such records and=20
<br>order the TUs accordingly, and otherwise fall back on the old-fashioned=
=20
<br>static initialization for libraries with no dependency list.
<br>
<br>> I'd like to ask a very BIG FAVOR of everyone here. Please 1000 tim=
es, lets
<br>> keep this discussion to the technical merits/faults and feasibilit=
y of this
<br>> idea. The subject of globals being never use evil vs necessary evi=
l and
<br>> dependency injection has been done over a million times. Please I =
beg of
<br>> you don't derail this thread into another one of those discussions=
..
<br>
<br>The next step sounds like a prototype extension to GCC or Clang. Good l=
uck!
<br></blockquote><div><br></div><div>I would be happy to do this. I want to=
gauge interest first. It doesn't make sense to spend a lot of time impleme=
nting a prototype version of this feature just to have the proposal shot do=
wn. Still, the function issue is rather scary. I'm surprised this doesn't s=
how up more often with iostream.</div><div> </div></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_2749_12191095.1384314376493--
.
Author: David Krauss <potswa@gmail.com>
Date: Wed, 13 Nov 2013 12:48:16 +0800
Raw View
On 11/13/13 11:46 AM, fmatthew5876@gmail.com wrote:
>
> On Tuesday, November 12, 2013 9:45:01 PM UTC-5, David Krauss wrote:
>> The next step sounds like a prototype extension to GCC or Clang. Good
>> luck!
> I would be happy to do this. I want to gauge interest first. It doesn't
> make sense to spend a lot of time implementing a prototype version of this
> feature just to have the proposal shot down. Still, the function issue is
> rather scary. I'm surprised this doesn't show up more often with iostream.
Again, real-world iostream implementations don't need to use the Schwarz
counter. The Standard simply sets a deadline late enough that a Schwarz
counter is applicable. I'm only familiar with GCC which uses a
nonstandard facility to force early initialization of the standard streams.
As far as I know, most folks use the inline wrapper function idiom with
its associated performance cost (a global access and predictable branch)
and bloat (several instructions to test the global and establish a
mutex). The boilerplate and costs are little enough for one size to fit
most.
Politically a good direction might be to frame it as a step towards
modules rather than satisfying an urgent practical need or improving
historical precedents. Practical needs are difficult to demonstrate
broadly and history has too many quirky details. Modules are
ill-defined, so co-opt them before they co-opt you :vP .
I do see a syntactic loose end: "explicit extern" works with objects
that are declared extern, but not static members which also have extern
linkage. You might also want to reserve "explicit static" member objects
for the same purpose, but it looks slightly more odd.
struct s {
explicit static int foo;
};
This is probably fine though. The intuitiveness rather hinges on the
reader's sense of what things might be explicit in a given declaration.
Ask the mailing list of your chosen prototype platform; they might
prefer an __attribute__ or reserved keyword instead of explicit.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
.
Author: David Krauss <potswa@gmail.com>
Date: Wed, 13 Nov 2013 17:43:24 +0800
Raw View
On 11/13/13 10:01 AM, fmatthew5876@gmail.com wrote:
> Now the linker, when combining all of these objects, can check the .symdeps
> sections of each object file and search for the symbol in the other object
> files to form a dependency graph. If a symbol in the .symdeps section of
> one object file is not found in another, its the same thing as normal
> undefined reference linker error.
Hadn't read this the first time through, but this might be a job for the
loader or a runtime initialization manager. You could have a shared
library which requires the user to initialize a shared global.
A missing definition is not an error when building a shared library. You
could arbitrarily say that all explicit dependencies must be resolved
within each linked binary file, but that doesn't fit the linkage model
or usage patterns very well.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
.