const reference optimizations

Started by
7 comments, last by Hway 23 years, 9 months ago
I am still having some problems understanding how I should define functions the "fastest" way. For example, originally projection''s prototype was something like this; D3DVECTOR C3d::project(D3DVECTOR v); Then, I decided to take it out from the class; (as well matrix it needed, it''s public anyway...) (shouldn''t have that much impact, AFAIK...) D3DVECTOR project(D3DVECTOR v); Still needs too much construction? D3DVECTOR project(D3DVECTOR *v); Could const reference be faster? D3DVECTOR project(const D3DVECTOR &v); And how about not needing to return a new vector? void project(const D3DVECTOR &v, D3DVECTOR &to); Now I can think only inlining as a next step... Am I on the right track here?
~~~ "'impossible' is a word in the dictonary of fools" --Napoleon
Advertisement
More or less on the right track:
the const reference is probably not faster than the passed pointer, however, it''s safer and more transparant to the user that way. Plus, knowing that the parameter is const might lead to some compiler optimisations.

Returning a new vector:
You might use a pointer return value, that doesn''t cost much.
If you''re going to have the target variable passed as a parameter, I would not make it a reference, but a pointer. That''s more obvious to the caller, there''ll be no mistaking that it''s a variable parameter.


Give me one more medicated peaceful moment.
~ (V)^|) |<é!t|-| ~
ERROR: Your beta-version of Life1.0 has expired. Please upgrade to the full version. All important social functions will be disabled from now on.
It's only funny 'till someone gets hurt.And then it's just hilarious.Unless it's you.
Passing a pointer and reference are the same thing to the compiler. In either case, marking it ''const'' is a good idea. It can help spot errors during compile-time rather than run-time, and could potentially give the compiler opportunities to optimize.

Returning a D3DVECTOR is okay, but if it is a call you make frequently, then placing it as a destination parameter as you did works fine.

Returning a pointer could be okay, but if you''re allocating memory (using ''new'') and returning it, you have the delicate job of knowing when it is appropriate to discard that memory. Efficient and complete memory management can be a bitch, so I opt to let the compiler do that as much as possible (and I do it as little as possible).

Returning a reference is not an option, if the item to be returned is created/allocated/local to that function. It will compile, but think about it... If you return a reference to a local (on the stack) variable, as soon as the function returns, that local variable is destroyed. You now have a bad reference. The problem then becomes timing; depending on when you use it, it may look like it''s working (if it hasn''t been overwritten yet) or not. It''s entirely unpredictable and shouldn''t be used.

Returning a reference to memory alllocated with ''new'' is safer, but still a bad option. Sometime later, you''re going to have to get the address of that reference so you can ''delete'' it. And depending on how you''re keeping track of references, how will you know when and where each reference is really a reference or a hidden pointer? If you''re going to do that, you''re better simply returning a pointer. And again, that brings up the memory management issues.

---- --- -- -
Blue programmer needs food badly. Blue programmer is about to die!
I would just like to point out that calling a function in a class (i.e. calling a method) is no more expensive than calling a ''regular'' function, unless the method is declared virtual, then there is a small performance hit when calling it (one extra indirect memory read).

A method compiles to a ''regular'' function with one additional implicit parameter, the ''this'' pointer.

If you already knew this or if optimization was not the reason for removing the method from the C3d class then please ignore me.


//Jesse
Actually Jesse, it is a bit more time consuming to call a member function. The implict this parameter will add another push and another pop, that's for sure. Okay, no biggie but I felt I should point it out . The below code was produced in VC6, debug mode.

        // void foo(void) {}193:194:  void foo(void)195:  {00401060   push        ebp00401061   mov         ebp,esp00401063   sub         esp,40h00401066   push        ebx00401067   push        esi00401068   push        edi00401069   lea         edi,[ebp-40h]0040106C   mov         ecx,10h00401071   mov         eax,0CCCCCCCCh00401076   rep stos    dword ptr [edi]196:      // do nothing197:  }00401078   pop         edi00401079   pop         esi0040107A   pop         ebx0040107B   mov         esp,ebp0040107D   pop         ebp0040107E   ret// void test::foo(void) {}189:  void test::foo(void)190:  {00401030   push        ebp00401031   mov         ebp,esp00401033   sub         esp,44h00401036   push        ebx00401037   push        esi00401038   push        edi00401039   push        ecx // this one doesn't exsist in the non-meber function0040103A   lea         edi,[ebp-44h]0040103D   mov         ecx,11h00401042   mov         eax,0CCCCCCCCh00401047   rep stos    dword ptr [edi]00401049   pop         ecx // this one doesn't exsist in the non-meber function0040104A   mov         dword ptr [ebp-4],ecx // this one doesn't exsist in the non-meber function191:      // do nothing192:  }0040104D   pop         edi0040104E   pop         esi0040104F   pop         ebx00401050   mov         esp,ebp00401052   pop         ebp00401053   ret        


Three more instructions! Oh my!!

"Paranoia is the belief in a hidden order behind the visible." - Anonymous

Edited by - Staffan on July 14, 2000 7:16:58 PM
Staffan:
I thought that VC 6 passed the ''this'' pointer in a register (ecx, I believe), the ''__thiscall'' calling convention. Thus not needing an extra push/pop pair (perhaps a mov or so).
Perhaps I remember incorrectly or perhaps this is only done in an optimized build...

Ok, I see now that the push/pop you''re talking about occurrs inside the functions, I thought you meant parameter pushing.
It''s not really fair to use unoptimized code now is it?
All the code you pasted in would reduce to a single ''ret'' instruction for each function.

It is true that a small performance hit occurrs because the compiler generates one extra ''lea'' instruction before a call to a method, that does not occur before a call to a function, other than that there is no real difference (that I can see, correct me if I''m wrong).
Though I doubt that it will be noticeable, considering that the body of the ''project vector'' function probably takes proportionately much longer than the intro/extro code for the function.

//Jesse
That last one was me, Jesse
Yes, the __thiscall calling convention does send the implicit this parameter in ecx. Okay so thiscall may add one instruction only, no biggie. I just felt I should point it out - I''m in this kind of mood today . And if the function/method actually did something it wouldn''t turn into just a ret.

"Paranoia is the belief in a hidden order behind the visible." - Anonymous
No, of course a real function would be compiled to more than a ''ret'', all I''m saying is that the three instructions you''re mentioning is in a bunch of junk-code that will be optimized away in a release build, I know that its not much to bother about....

Enough said, no need to argue about little things like this...

Have a nice day/night...

//Jesse

This topic is closed to new replies.

Advertisement