views:

149

answers:

7

I have always been taught that non-primitive types should be passed by const reference rather than by value where possible, ie:

void foo(std::string str);//bad
void foo(const std::string &str);//good

But I was thinking today that maybe actually some simple user defined types may actually be better passed by value eg:

class Vector2
{
public:
    float x, y;
    ...constructors, operators overloads, utility methods, etc...
};

void foo(Vector2 pos);
void foo(const Vector2 &pos);//is this really better than by value?
void foo(float x, float y);//after all isn't by value effectively doing this?

My thought is that by passing the Vector2 by reference, it is actually more expensive than passing by value since the compiler is now using a pointer and dereferencing to access the const Vector2 &pos version?

Is this the case? Are simple objects best off passed by value? Where should the line be drawn?

+6  A: 

Yes, simple objects should be passed by value. The line has to be drawn according to the architecture. If in doubt, profile.

Peter G.
+1 for profiling -- its the only way to tell which is better
Chris Dodd
+1  A: 

Passing by const reference avoids the construction of a new object. If your constructor is non-trivial, e.g., it allocates memory, you will be much better off passing by const reference than by value.

In the C# world, you make this decision by choosing whether to make something a class or a struct. Classes use reference semantics while structs use value semantics. Everything I've ever read says that you should generally choose to make everything a class unless it is very small, i.e., on the order of 16 bytes. If you are looking for a cut-off for when to pass by value versus const reference in C++, 16 bytes seems like a reasonable threshold.

Matt Davis
POD types don't have non-trivial copy constructors (or indeed non-trivial default constructors or destructors either).
Ben Voigt
The OP didn't say explicitly say POD type. He said **simple** user-defined type and then gave an example that indicated it had a constructor.
Matt Davis
A: 

My thought is that by passing the Vector2 by reference, it is actually more expensive than passing by value since the compiler is now using a pointer and dereferencing to access the const Vector2 &pos version

It would be true if you passed an object where size_of(object) < size_of(pointer_to_object). For example, char const& might be more expensive than char

a1ex07
It can also be true if the repeated dereferencing will result in more overhead than is saved by not passing as much data. Or if the reference prevents optimizations due to aliasing concerns. Or if the reference hurts your locality.
Dennis Zickefoose
+1  A: 

Just as a matter of policy I pass any object that isn't a basic C data type by const reference. Its much easier to remember that way.

T.E.D.
A: 

trying hands on memory....(all for 32 bit system)

passing now depends upon data type

if its struct only pointer will be passed..(MEMORY EAT UP=4B)

Now if your making copies obiviously its gonna hit your ram................

peril brain
Prasoon Saurav
+1  A: 

An older, yet lucid, analysis of the ins-n-outs of passing parameters can be found at http://www.ddj.com/184403855. Of course c++0x obviates a lot of such issues with move semantics, but the paper provides a lot of justification for why move semantics are desirable.

rlduffy
+1  A: 

One factor I've not seen mentioned is what the routine is going to do with the passed-in value. Unless the routine is expanded inline, manipulating data which are passed by reference will require more code than manipulating data which are passed by value. If the fields of the passed-in structure will on average be accessed less than once each, this extra overhead will be small compared with the overhead of copying the structure. If they will on average be accessed many times each, it would likely be better to have them on the stack. If the interface is already set as pass-by-reference for a structure which is heavily accessed, it may make sense for the called routine to copy all parts that are of interest. On the other hand, if the called routine is going to copy much or all of a structure anyway, it may as well be passed by value.

supercat