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