Re: Validity of pointer conversions
On Jan 8, 2:18 pm, Ioannis Vranos <j...@no.spam> wrote:
James Kanze wrote:
All objects (even those with user defined constructors) with
static lifetime are zero initialized before program
start-up, however.
I assune you mean they are initialised in the style
T obj= T();
for these objects, since those with user defined constructors
may be not possible to initialise with 0.
No, since if T has a non-trivial constructor, it has dynamic
initialization. Formally, initialization of variables with
static lifetime takes place in three steps:
1. Zero initialization. This takes place before any other
initialization, and affects *all* objects, regardless of
type.
Zero initialization of an arithmetic type, and enum or a
pointer is the same as initializing it with 0, converted to
the corresponding type. (Note that it does *not*
necessarily mean all bits zero, although this is the case on
most frequent architectectures.)
Zero initialization of a reference means nothing.
Zero initialization of a class type or an array means zero
initialization of each of a its elements. This recurses
down until you get to something in one of the above cases.
2. Static initialization. This concerns arithmetic types,
pointers and enums initialized with a constant expression,
and class types with trivial constructors initialized with
the aggregate initialization syntax in which all of the
initializers are constant expressions. It also concerns
arrays all of whose elements can be statically initialized.
3. Dynamic initialization. All of the rest, this involves
execution of code (which in turn can mean order of
initialization issues).
In practice, since static initialization doesn't involve
execution of code, there's no way a program can tell whether
zero initialization took place or not. The first line of code
you wrote only gets executed after static initialization is
finished. On the other hand, it is quite possible to observe
the "double" initialization when dynamic initialization is
involved:
#include <iostream>
extern int f() ;
struct Toto
{
int a ;
Toto() ;
} ;
Toto t ;
int b = f() ;
int f()
{
return 42 ;
}
Toto::Toto()
: a( b )
{
}
int
main()
{
std::cout << t.a << std::endl ;
return 0 ;
}
This program is guaranteed to output 0.
More generally, I use this to ensure correct initialization of a
singleton during static initialization (and thus, normally,
before threading starts).
(Technically, I'm not sure, but I think an implementation is
allowed to scribble over the memory before calling a
constructor, but practically, none do, and in some very
exceptional cases, I've also exploited this to allow objects to
be used before being constructed.)
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34