tags:

views:

216

answers:

4

Hi to all!
Assuming I have this class in C++:

class A
{
public:
    static const TDouble pi_d;
    static const TDouble pi;
    static const TDouble div;
};

They are initialized at the .h file in the following way:

const TDouble A::pi_d = 3.14;
const TDouble A::pi   = A::pi_d;
const TDouble A::div  = A::pi / 180.0;

When I print the member div the result is 0.0000. If I change this line:

const TDouble A::pi   = A::pi_d;

with this line:

const TDouble A::pi   = 3.14;

then everything is OK and a correct value is printed.

Do you know what is the reason for that?

Thank you for your time. Asaf.

+1  A: 

It's impossible to answer this question unless you give us more information on what exactly a TDouble type is.

My guess from the sample is that TDouble has either a lossy conversion error or does not properly implement the / operator (essentially converting to int before dividing). But it's just speculation unless we see the type.

JaredPar
sorry, your'e right. typedef double TDouble, so I didnt implement the / operator.
In which case there should be no problems there. "double" is a POD type (Plain Old Data), and comes with arithmetic operators already defined.
David Thornley
I think that too, but still I have this problem and I want to know the cause for that.
A: 

Order of initialzation of static members isn't defined. Relying one one static member to initialize another is not going to work reliably. It's unlikely you really need two constant static members, so I'd say just eliminate one.

Of course, it's likely your actual code has something more subtle going on. Just remember that you can't count on order of initialization of constants any more than you can count on order of initialization of fields in a constructor init list, and write your code accordingly. An occasional macro can help.

#define PI 3.14
const TDouble A::pi_d = PI;
const TDouble A::pi   = PI;
const TDouble A::div  = PI / 180.0;

That works because macros are textual replacement, and can't be re-ordered the way static member initializations can.

Michael Kohne
I'd also add that they should be initialized in a cpp file not a header file.
Tom
In a compilation unit, the order *is* defined. Between compilation unit, it isn't.
AProgrammer
Hi,I know I can eliminate one of them but I want to understand the problem. That holds also for the define. I want to know why it happens.I also thought that the init order is different. I know the order is set according to the definition in .h file, isn't it?
Tom, why should they initialized in .cpp file and where? inside the class I cant because the type is double, and outside the class has the same effect as defining them in .h file
It looks like the order of initialization is well-defined in this case (see my answer). Since this is in one translation unit, the initialization should be done in the given order.
David Thornley
@Asaf, initializing them in the .h file means that each translation unit that #includes the .h will get its own storage for the static members. At link time, the linker will likely choose which storage to use (you may get link warnings for this). Depending on what the linker chooses, you could have trouble with the Static Initialization Fiasco.
Fred Larson
Rubbish: The order of initialization is well defined. Within a translation unit the order of initialization is the same as the order of declaration.
Martin York
You implication that the order of initialization of members in the initialization list is not defined is misleading. I know what you mean but I have read the standard. Beginners without this knowledge will find the wording confusing.
Martin York
+2  A: 

The Standard, 3.6.2, says that such initialization should work, making a few assumptions.

"Objects of POD types (3.9) with static storage duration initialized with constant expressions (5.19) shall be initialized before any dynamic initialization takes place." Therefore, the assignment of 3.14 should happen before any other initialization.

"Objects with static storage duration defined in namespace scope in the same translation unit and dynamically initialized shall be initialized in the order in which their definition appears in the translation unit." Since pi appears before div in the definition, it should be initialized first.

I'm assuming that the statements are as you gave them, and that TDouble is some sort of fancy version of double. If TDouble is a class with real behavior, that complicates things. Similarly, you aren't showing the context of the code, or even whether the .h file is #included in more than one .c file (in which case you'd have problems with the One Definition Rule). Alternatively, you might not be using a standard-conformant compiler.

So, what's the definition of TDouble? What's the context for the lines? What compiler are you using, and with which compiler options?

Initialization like this is not good style, partly because minor changes in the code or how you use it can cause bugs, but this should work as far as I can tell.

David Thornley
+7  A: 

The answers referring to "initialization order of statics" are correct for objects that are defined in different translation units but within the same TU the order is defined:

9.4.2/7:

Static data members are initialized and destroyed exactly like non-local objects (3.6.2, 3.6.3).

3.6.2/1:

Objects with static storage duration defined in namespace scope in the same translation unit and dynamically initialized shall be initialized in the order in which their definition appears in the translation unit.

Your definitions are ordered correctly, and so they should be initialized in the correct order. I would go with the comment by AProgrammer regarding the multiple definitions. Unlike non member const objects, your objects have external linkage:

3.5/5:

In addition, a member function, static data member, class or enumeration of class scope has external linkage if the name of the class has external linkage.

If the header file is included into multiple translation units, then the code violates the ODR and it is my guess that the resulting undefined behaviour is the strangness with the initializations. Try putting the definition of the static members into a single source file and see what happens.

Richard Corden
The ODR applies if the .h file is included in more than one .c file.
David Thornley
Thanks David. Updated the text.
Richard Corden