zero initialization.

W

werasm

Hi all,

I recently just stumbled upon this code. According to what
I see in the standard it should be fine, but I've always done
the initialization explicitly myself:

//.h
//...
struct X
{
static Y* m_Y;
};

//.cpp
//To initialise...
Y* X::m_Y; //...1
//as opposed to...
Y* X::m_Y = NULL; //...2

I now know (1) is correct as well (from various areas in the
standard).
I personally prefer (2) - probably because I've always done it that
way (I think I might have even had a problem with (1) a couple
of years back).

Any thoughts on this? Do I understand the standard correctly if I
say (1) is OK?

My rationale from std98:
- 8.5:5 - to zero initialize...
- 3.6.2 - storage for objects with static storage...

Which method do you consider preferred, or is it a matter of taste?

Regards,

Werner
 
R

Rahul

Hi all,

I recently just stumbled upon this code. According to what
I see in the standard it should be fine, but I've always done
the initialization explicitly myself:

//.h
//...
struct X
{
static Y* m_Y;

};

//.cpp
//To initialise...
Y* X::m_Y; //...1

I think static variables stored in the data segment bss, are always
initialized with 0...
just like global variables...
 
V

Victor Bazarov

Rahul said:
I think static variables stored in the data segment bss, are always
initialized with 0...

To clarify...

It is unspecified what "segment" they are stored in, and there is no
reference to "bss" in the C++ language standard. Objects with static
storage duration have their memory zero-initialised before any other
dynamic initialisation takes place. If no other initialisation is
expected, the zero-filled memory is it.
just like global variables...

Global variables (declared at the namespace level) all have static
storage duration (if they have storage at all, that is).

V
 
J

jg

Which method do you consider preferred, or is it a matter of taste?
I think that (2) is preferred. A 'static member' means that all
objects
of X shares the same member. The 'static' here does not require
that 'my_Y' be in static storage, although it is in fact true in many
implementations.

JG
 
V

Victor Bazarov

jg said:
I think that (2) is preferred. A 'static member' means that all
objects
of X shares the same member. The 'static' here does not require
that 'my_Y' be in static storage, although it is in fact true in many
implementations.

I am not sure what "be in static storage" means here. Static class
data members are said to have static storage duration (see Standard,
[basic.stc.static]/4). Does that mean that they are "in static
storage"? Probably. If their storage has duration that is static,
then you can call their storage "static", and since those objects
are _in_ their storage, then it's OK to say that they are "in static
storage".

So, to argue, the Standard clearly _requires_ that static data
members "be in static storage". It has to be true for all compiler
implementations, otherwise they are not conforming.

V
 
J

jg

I think that (2) is preferred. A 'static member' means that all
objects
of X shares the same member. The 'static' here does not require
that 'my_Y' be in static storage, although it is in fact true in many
implementations.

I am not sure what "be in static storage" means here. Static class
data members are said to have static storage duration (see Standard,
[basic.stc.static]/4). Does that mean that they are "in static
storage"? Probably. If their storage has duration that is static,

Yes, this was what I meant.
then you can call their storage "static", and since those objects
are _in_ their storage, then it's OK to say that they are "in static
storage".

So, to argue, the Standard clearly _requires_ that static data
members "be in static storage".

You're probably right. The 9.4.2.6 says it has external linkage.
Does it mean it is definitely a static/global, so it shall be
automatically zero-initialized ?

JG
 
J

jg

You're probably right. The 9.4.2.6 says it has external linkage.
Does it mean it is definitely a static/global, so it shall be
automatically zero-initialized ?

I found the answer for myself, 3.7.1(4) states a static member has
static storage duration.

Back to the original question, I think it is better to use
explicit initialization.

JG
 
D

Daniel T.

werasm said:
I recently just stumbled upon this code. According to what
I see in the standard it should be fine, but I've always done
the initialization explicitly myself:

//.h
//...
struct X
{
static Y* m_Y;
};

//.cpp
//To initialise...
Y* X::m_Y; //...1
//as opposed to...
Y* X::m_Y = NULL; //...2

I now know (1) is correct as well (from various areas in the
standard).
I personally prefer (2) - probably because I've always done it that
way (I think I might have even had a problem with (1) a couple
of years back).

Any thoughts on this? Do I understand the standard correctly if I
say (1) is OK?

My rationale from std98:
- 8.5:5 - to zero initialize...
- 3.6.2 - storage for objects with static storage...

Which method do you consider preferred, or is it a matter of taste?

Guru's generally recommend making things explicit in code rather than
leaving them implicit, so your (2) would be the preferred thing to do.
 
P

Pete Becker

Guru's generally recommend making things explicit in code rather than
leaving them implicit, so your (2) would be the preferred thing to do.

Yes, there are "gurus" who don't believe that programmers ought to be
held to professional standards. So they tell us you shouldn't leave
static data implicitly initialized, because someone reading your code
might not know what that means, or, worse, might know what it means,
but think that you might not know what it means, and that you only got
the right result by accident.
 
W

werasm

Yes, there are "gurus" who don't believe that programmers ought to be
held to professional standards. So they tell us you shouldn't leave
static data implicitly initialized, because someone reading your code
might not know what that means, or, worse, might know what it means,
but think that you might not know what it means, and that you only got
the right result by accident.

Hmmm, does this mean you also suggest the latter?

Regards,

Werner
 
D

Daniel T.

Pete Becker said:
Yes, there are "gurus" who don't believe that programmers ought to
be held to professional standards. So they tell us you shouldn't
leave static data implicitly initialized, because someone reading
your code might not know what that means, or, worse, might know
what it means, but think that you might not know what it means, and
that you only got the right result by accident.

Much like the common recommendation that one should never put leading
underscores on variable names simply because in some contexts such a
variable is reserved.

The less context dependent a rule is, the easier it is to remember. "int
foo = 0;" makes 'foo' equal 0 no matter the context, for "int foo;",
'foo' will equal 0 in some contexts and be undefined in others.

But I take your point that some Guru's tend to talk down to people.
 
J

James Kanze

Yes, there are "gurus" who don't believe that programmers ought to be
held to professional standards. So they tell us you shouldn't leave
static data implicitly initialized, because someone reading your code
might not know what that means, or, worse, might know what it means,
but think that you might not know what it means, and that you only got
the right result by accident.

I don't think it's a question of someone not knowing; it's a
question of being explicit; in many ways, a way of saying that
you did know (and didn't just forget the initialization).
Whether that's important or not in a specific context depends on
the community practices; the implicit zero initialization of
static variables seems wide spread enough that I wouldn't
necessarily insist on explicit initialization. But a lot
depends on the context---if the initialization is for a
particular value, which just happens to be 0, I'd argue for
making it explicit, whereas in the case of e.g. pointers, where
zero is a very special value, and not just one of many, I
generally don't bother myself.

There are also special cases where you count on zero
initialization to detect that dynamic initialization hasn't
occured yet (in order to manage order of initialization). In
such cases, you obviously can't make the zero initialization
explicit.
 
W

werasm

There are also special cases where you count on zero
initialization to detect that dynamic initialization hasn't
occured yet (in order to manage order of initialization). In
such cases, you obviously can't make the zero initialization
explicit.

Could you perhaps (please) elaborate on the adverse effects of
making zero initialization explicit in the last case mentioned.
It is still not so obvious to me.

Regards,

Werner
 
V

Victor Bazarov

werasm said:
Could you perhaps (please) elaborate on the adverse effects of
making zero initialization explicit in the last case mentioned.
It is still not so obvious to me.

I think James is talking about detecting that a static object has
not been dynamically initialised yet, for example:
---------- module_one.c++
SomeClass* SomeClass::eek:urSharedInst = new SomeClass;
---------- module_two.c++
int globalImportantInteger = SomeClass::eek:urSharedInst->foo();
----------

In this case 'SomeClass::eek:urSharedInst' is dynamically initialised
and in the other module it's _used_. This will lead to undefined
behaviour if 'ourSharedInst' is initialised _after_ the integer.
A way to prevent UB would be:
---------- module_two.c++
int globalImportantInteger = SomeClass::eek:urSharedInst ?
SomeClass::eek:urSharedInst->foo() : 42;
----------
Since 'SomeClass::eek:urSharedInst' is static, it's zero-initialised
before dynamic initialisation, allowing checking it for NULL, I
believe.

Anyway, as James said, those are really REALLY special cases and
shouldn't be viewed as idiomatic use of the fact that static
storage is zero-filled upon program start.

V
 
W

werasm

I think James is talking about detecting that a static object has
not been dynamically initialised yet, for example:
---------- module_one.c++
SomeClass* SomeClass::eek:urSharedInst = new SomeClass;
---------- module_two.c++
int globalImportantInteger = SomeClass::eek:urSharedInst->foo();
----------

In this case 'SomeClass::eek:urSharedInst' is dynamically initialised
and in the other module it's _used_. This will lead to undefined
behaviour if 'ourSharedInst' is initialised _after_ the integer.
A way to prevent UB would be:
---------- module_two.c++
int globalImportantInteger = SomeClass::eek:urSharedInst ?
SomeClass::eek:urSharedInst->foo() : 42;

OK. I agree - also I agree that globalImportantInteger's
initialization is dynamic, as it is not zero initialised and it
is not a constant expression. However, if SomeClass::eek:urSharedInst
looks like:

SomeClass* SomeClass::eek:urSharedInst = NULL;

It is a constant expression and therefore shall be initialized
before dynamic initialization takes place (perhaps not before zero-
initialization). This means that it would still work in the example
given by you (meaning it would still be NULL when checked).

Is this right? If so, hence my not understanding the obvious
mentioned by James.

Regards,

Werner
 
J

James Kanze

Could you perhaps (please) elaborate on the adverse effects of
making zero initialization explicit in the last case
mentioned. It is still not so obvious to me.

The main adverse effect is that it isn't possible to do it.
Consider something like:

Singleton* Singleton::eek:urInstance = &Singleton::instance() ;

Singleton&
Singleton::instance()
{
if ( ourInstance == NULL ) {
ourInstance = new Singleton ;
}
return *ourInstance ;
}

In this case, the dynamic initialization is to ensure that
Singleton::instance is called at least once before main is
entered. And thus, presumably, before threading starts and we
need a lock. In other cases, you may simply want to test
whether dynamic initialization has taken place or not.

You can, of course, always explicitly initialize with null, and
then use some other trick to trigger the dynamic initialization,
e.g. something like:

Singleton* Singleton::eek:urInstance = NULL ;
bool thisVariableIsNeverUsed
= (Singleton::instance(), true) ;

Singleton&
Singleton::instance()
{
if ( ourInstance == NULL ) {
ourInstance = new Singleton ;
}
return *ourInstance ;
}

I would hope, however, that the fact that variables with static
lifetime are zero initialized is widely enough known that such
extra trickiness (which IMHO doesn't make the code clearer in
the least) not be necessary.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top