Sign in to follow this  
kRogue

at what size should one call by reference..

Recommended Posts

Silly quasi-preformance question, but here goes: at about what size of a structure should one shift from calling by value to calling by reference? The reason one calls by value is that it gets copied to the stack which is faster to access than calling by reference which will access the heap, so typical example:
struct myStruct 
{
  /* data, but not so much data */
};


/*so which would be better: */

void myFunction(const struct myStruct *p_data)
/* C++ folk would use const struct myStruct &data*/

/* or */

void myFunction(const struct myStruct data)

at what size of myStruct (say on a modern PC) would be best to stick with call by value? -kRogue

Share this post


Link to post
Share on other sites
It depends on how you use the variable within the function. There is no easy answer, so just pick a convention and stick to it. Worst case, see how things are behaving in that function later, and make a decision based on actual use rather than conjecture.

CM

Share this post


Link to post
Share on other sites
in the case I am concerned with at this moment, the data is a float matrix(4x4) so 16 floats, for a total of 64 bytes... the usage is basicly once for each object for each frame (of some 3D stuff)... me thinks I will make this one call by reference since it is passed along to an openGL API call which takes the data by reference anyways... but the more general case is still an important perfomance issue actually...

Share this post


Link to post
Share on other sites
My personal preference is basically whatever fits within a register on the target platform. For the most part, this is 32 bits.

In other words, almost all of my structures or classes are passed by pointer or reference. Only numeric types (integers, floating point, etc) are passed directly.

It's a coding habit I've carried over for the many years I worked with assembly and C. Can't seem to shake it. :)

Share this post


Link to post
Share on other sites
Quote:
Original post by bpoint
My personal preference is basically whatever fits within a register on the target platform. For the most part, this is 32 bits.

In other words, almost all of my structures or classes are passed by pointer or reference. Only numeric types (integers, floating point, etc) are passed directly.


It's the same with me. Now that I'm working almost exclusively with C++ with my personal projects, if I'm sending a pointer to some memory, or something that could possibly be not there that I can indicate with NULL, then I'll use a pointer. With most of my object's I'm using references because my objects are generally bigger than 4 bytes, or have a large amount of allocated memory which would have to be copied over to a new object if passed by value.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
No, you're wrong with your example, c++ guys would use c++ not that c and c++ mixed thing you've written there.

Use by value for all built-ins and small PODs (8bytes and smaller) and of course use them too if you _need_ a copy. By reference if you have to change the value(s), or if the type(s) are non built-in types

Share this post


Link to post
Share on other sites
I use, in the order of preference:
1) TYPE for PODs
2) const TYPE& by default
3) TYPE& for mutable arguments
4) TYPE*
5) TYPE

So if myFunction does not mutate your argument, use const myStruct&. Otherwise, use myStruct&.

hth,
CipherCraft

Share this post


Link to post
Share on other sites
Quote:
Original post by kRogue
...but the more general case is still an important perfomance issue actually...

Sure, but in the general case the performance question can't be answered.

CM

Share this post


Link to post
Share on other sites
if (size > machine_word) use_reference;

Addendum: if (is_smart_pointer) use_const_reference;

[Edited by - _goat on March 28, 2006 9:02:27 AM]

Share this post


Link to post
Share on other sites
I would add that size is not the only criterion for choosing between passing by reference or value. Constructor complexity is definitely a concern as well. For POD types, sure, constructor complexity is definined entirely by how many bytes need to be copied, so size is the only relevant factor. But outside of POD types, constructors could have all manner of different complexities. Usually size and complexity are roughly correlated, but not always.

Share this post


Link to post
Share on other sites
It depends on how the parameter is used, for example:

You'd normally pass a container by reference - but if you need a local copy in the function anyway, passing by reference is just a waste.

It also depends on the copying cost - it's possible to have a class that holds an object by pointer, then deep copies the pointed to object when it's copied. Such an object would be the size of the machines registers, but would be expensive to copy.



Share this post


Link to post
Share on other sites
For me, I rarely pass POD types by reference. I just pass those by value. If it's a struct or class, and it's not going to be changed inside the function, then I'll pass by const reference; however, if the class or struct is to be altered, then I'd pass by reference. Rarely do I pass by pointers anymore; but, that's due to the set of conventions I set for myself. Since I started using boost, if I ever need to pass a pointer around, I'd use one of the smart pointer classes you get with it. I also toss my long-term pointers (excluding dynamic arrays) into smart pointers to take care of the off chance that I may end up with invalid pointers floating around.

Share this post


Link to post
Share on other sites
It also depends on platform. For the XB360 microsoft recommends passing their native vectors and such by values because their registers are huge and it's faster than passing a reference, cache-wise. But yea agree with everything said above about PC. _goat summed it up pretty well, with the addition of const to the reference unless you need to modify it in the function, and avoid passing by * in C++ unless theres some reason the argument should be allowed to be null for some special behavior.

Share this post


Link to post
Share on other sites
Many compilers also have special-case calling conventions for arguments that are equal to 2*register size which makes passing the by value efficient. This question falls firmly into the realm of "it depends".

IMHO reasonable defaults for pass-by-value are "type" for primitives and "const type &" for non-primitives. In relatively rare cases where you want pass-by-value but are going to party on the parameter in the function anyway then you don't really lose anything by using "type" for non-primitives.

Oh, and calling by reference doesn't do anything to the heap. References are really just pointers in disguise and they will happily point to stack objects as well as heap objects.

Share this post


Link to post
Share on other sites
for a PC, simple vec3,vec2,vec4 and float3x3, float4x4, float2x2 very simple classes, it looks like the rule of tum for it is pass by const reference (which is what I usually do), but vec3 is just 3 floats... we are talking small stuff, and float4x4 is 16 floats (64 bytes) which for 64-bit CPU's fits into 8 registers... (maybe that is too many) oh well.... it is very easy to change one's .hpp files from pass by value to pass by const reference for these situations, but still leaves me with the question which one? [possibly it does not matter a great deal since I only do maybe 100-200 of these vec/vec, matrix/matrix, vec/matrix calls per frame of drawing anyways, but still... jsut curious from others experience.)


Share this post


Link to post
Share on other sites
Well, I'd just call those functions a few 1000 times and simply take the time they need... then you know exactly wich of them is the faster one

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this