Jon,

I guess that you will know the final outcome of my opinion, but I will now 
tell in detail why:

On Dienstag, 9. M�rz 2004 03:52, Jon Berndt wrote:
> Are there any reasons to choose one method over the other in the
> declaration of local variables that are used each frame?
Yep.

I want to comment that in a different order you have choosen to give the 
examples.

> ============= Method 3)
>
> class MyClass {
>   double abc;
>   void Calculate(double);
> };
>
> MyClass::Calculate(double xyz)
> {
>   ... <calculations> ...
>
>   if (price_of_tea_in_China > 0.45) {
>     abc = xyz*1.5;
>   }
>
>   ImportantValue = abc+24.0;
>
>   ... <more calculations> ...
> }
Several points here:
1. The state of the abc value needs to be saved in memory at the exit of 
Calculate. Needless operation since it is never used outside.
2. Uses needless memory.
3. The compiler is not free to reorder computations using/writing this abc 
value for better scheduling. For example if you call an arbitraty function 
somewhere in Calculate the compiler cannot reorder computations using the abc 
value across this function call. The reason for this is that, if the MyClass 
class itself is not a local, stack allocated, class itself, the compiler 
cannot know if the address of this class is ever taken somewhere in an other 
source file. Thus it will simply assume that it is taken at some time. Also 
it could be the case that a reference of the class instance is used somewhere 
in my hypotetical function call. And if this is used there the class has to 
be in the defined state the coder wrote in the code. This means the compiler 
is more bound to the computation order you give it.
4. In my eyes it screws up some of the ideas of object orientation. Class 
members will store the _persistent_ state of the class object. A class itself 
is not a temporaries memory hog.

So, why is reordering so important. It is because of pipelined cpu's which 
will have pipeline stalls when they have to issue an operation which depends 
on a result of a prior operation. So if a compiler is able to reorder 
computations in a way that there are enough instructions in between the 
computation of the prerequisite value and the usage of this value, it does 
not have to wait and though executioin will be faster.

Also it disturbs the code reader, at least me, who wonders why these localy 
used values are defined in class.

> ============= Method 1)
>
> MyClass::Calculate(double xyz)
> {
>   double abc;
>
>   ... <calculations> ...
>
>   if (price_of_tea_in_China > 0.45) {
>     abc = xyz*1.5;
>   }
>
>   ImportantValue = abc+24.0;
>
>   ... <more calculations> ...
> }
This is much better, since it uses local memory which is under the full 
control of the compiler. No, so called, sideeffects.
One little thing which is not present for the double values used in this 
example, but is more important for class es having an initializer function. 
Imagine this double will be a FGColumnVector3, then at the declaration the 
default initializer will be called and later the operator=(...) function. So 
the class is initialized at function start and later completely overwritten. 
Which is obvoiusly too much initialization.
BUT, compilers are not so simple minded programms. I am shure that life 
analysis of most compilers (including gcc) will track down this issue for 
native types like double values and for really simple classes. I would at 
least *hope* that it will also see that the class initializer could be 
optimized away mostly. Here the Debug(int) call in your usual classes my be 
something which prevents this optimization. I am not shure about this.

> ============= Method 2)
>
> MyClass::Calculate(double xyz)
> {
>   ... <calculations> ...
>
>   if (price_of_tea_in_China > 0.45) {
>     double abc = xyz*1.5;
>   ... <more calculations> ...
>
>   ImportantValue = abc+24.0;
>   }
>
> }
So here I used the fixed example which really compiles and ilustrates what you 
were asking.
I think that this is the way to go. For the double value in the example this 
is definitly aequivalent to the above example due to smart enought compilers. 
But for a class value like a vector this will also call an initalizaton 
function, but this is exactly the right one and not one which does redundant 
work. Also the operator=(...) call is not done here.

I would prefer to use this one. At least for class valued variables. Once I 
was used to that I also have done the same with simple native types. It is 
then simply more consistent to use the same style.

> The general question boils down to this: Is it better to declare local
> temporary variables actually as class members, or simply locals (and, if
> so, does it matter whether they are declared at first use or at the
> beginning of the function in which they appear)?
So the general answer is a bit more dificult. That depends. If you have huge 
objects which are expensive to allocate and destroy, it may be sensible to 
allocate it once. Also huge objects may overflow the stack, so the need to be 
allocated by new and destroied by delete which is more expensive than just 
allocating stack space which is done on the fly at function entry and exit. I 
would regard this as a kind of special case.
For small objects like our vector classes I definitly think that using 
temporaries is the right thing.

   Greetings

       Mathias

-- 
Mathias Fr�hlich, email: [EMAIL PROTECTED]

_______________________________________________
Flightgear-devel mailing list
[EMAIL PROTECTED]
http://mail.flightgear.org/mailman/listinfo/flightgear-devel

Reply via email to