Jump to content
  • Advertisement
Sign in to follow this  
okonomiyaki

Do you return const references?

This topic is 4387 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Say I have a Transform object that holds a Vector3f object (vector of 3 floats obviously) for translation. I don't mean to early optimize, but I am, and I can't help thinking of saving a copy by returning a const reference when asking for it.
const Vector3f& GetTranslation() { return m_Translation; }
I can't think of any reason not to do this. It will always be copied over when used as in an expression or assignment, so you could still do things like
Vector3f Trans = TransformObj->GetTranslation();

or

Vector3f SomeTrans = TransformObj->GetTranslation()+OtherTrans;
And it makes me feel better about calling GetTranslation().x (or y or z) multiple times. The only downside is that the function could never dynamically calculation a translation value and return it, but if I can apply that restraint, is there anything wrong with doing this?

Share this post


Link to post
Share on other sites
Advertisement
I may be wrong, but I believe any decent compiler will optimize a non const reference return value to not make the extra copy.


jfl.

Share this post


Link to post
Share on other sites
Quote:
Original post by jflanglois
I may be wrong, but I believe any decent compiler will optimize a non const reference return value to not make the extra copy.


jfl.


No, I'm comparing it to


Vector3f GetTranslation() { return m_Translation; }


Which, by the standard I believe, is passed by value. That optimization seems dangerous, as if the return value is ever altered, really weird affects would occur when I don't expect it to be altered. Does it really check to see if it's never touched and not do the extra copy?

Share this post


Link to post
Share on other sites
The compiler MAY optimize certain things, but I would always return a const ref in the case you are referring to. i.e.

const Vector3f& GetTranslation() const { return m_Translation; }

I would also never return an object by value assuming the compiler would optimize it. IMHO that is bad coding practice, not to mention certain bugs can be avoided by specifing the method signature returns a const ref.

Share this post


Link to post
Share on other sites
I personally wouldn't return a Vector3f as a reference, because I don't think the saving of copying a couple floats is worth it. However, I ways return larger things like Matrix3x3f as references, or anything that will result in an expensive copy operation like std::string, etc.

Share this post


Link to post
Share on other sites
Your return type should be dictated first of all by the semantics you want - optimization is a secondary concern. Since Vector3f is likely to be a very small type anyway, speed issues can be completely ignored (even as a secondary concern) until you find that there is a bottleneck caused by this function.

So, the difference in semantics is what should guide you. In this case, it only makes a difference in a fairly unusual case:

If GetTranslation returns a const reference:

Transform foo;

const Vector3f &foo_translation = foo.GetTranslation();

foo.Translate(Vector3f(10.0f, 5.0f, 15.0f));

// foo_translation has now changed
// (assuming an obvious implementation of Transform)




Whereas, if GetTranslation returns a value, foo_translation will not change.

Of course, most of the time you'll either use the result directly, or store it in a variable directly (not assign it to a reference), and so it won't make any difference.

Personally, I would return a value, because I think GetTranslation() should probably return a snapshot of the current translation value, not a reference to a value that may change in the future.

Edit: One thing is certain though, the GetTranslation function itself should be marked const, since it does not modify the contents of the Transform object. ie: Vector3f GetTranslation() const { ... }

John B

Share this post


Link to post
Share on other sites
In programming the small things like copying objects adds up. If you have expression:

float3 n = normalize(a + b * length(c)) + cross(a - b, a - c);

Suddenly HALF the work is copying values around, not actually doing the computations which we intend to to. The ONLY thing here we are interested are n.x, n.y and n.z - the faster we get them the better we are off.

This case doesn't give much leverage for using const reference return values but that's life. :)

One important factor to notice for this thread's sakes is NRVO (Named Return Value Object), it wasn't until fairly recently that Microsoft products started implementing this optimization strategy. They still don't do it perfectly, experimentation to find the facts yourself (tm) is advised. Also pay heed that on different compilers like g++ the rules are again different, it all depends what tools you use. And another warning that should be said is that when again new Microsoft compiler comes out thigns could turn around once again.

The *safest* thing to do is to do the RIGHT THING (tm) to begin with. Then you're not at the mercy of the latest compiler so much. Good, solid code rarely goes slower with the latest compiler upgrade so you guys should be safe when you do the RIGHT THING (tm).

It's up to everyone himself to figure it out what the RIGHT THING (tm) for them. If someone wants to return by value when const reference would do the trick just tandy, that's their call. So what if the value is "optimized" out, that's on the compiler you use today what about tomorrow? What about other platform, other compiler?

x86 is a common compiler am I wrong and Windows is a common platform, right or wrong? Likewise, why care about petty things like endianess or alignment, why bother, those always worked out for my (insert name of my windows application here)

Share this post


Link to post
Share on other sites
I usually prefer returning const references to instances, if the instances consist of several 32-bit variables like matrices.

Though, if you would have a function like "const Vector3f& GetTranslation" and it's not compiled inline it returns a reference/address to the vector. Then when the vector member variables are accessed it's done by addressing the memory location of the variables. If the vector is located in the heap memory how fast access is depends on if it's already in the cache memory for the processor or not. It's likely to be in the cache but if it's not in the cache it'll be slow to get it all the way from the RAM.

If the vector had instead been returned as a copy and stored in a local variable, then access to its member variables is done using an offset value in the stack memory. The local stack memory is probably more likely to be in the cache memory since the local code block is currently executed on the CPU, and in the cache.

But like already discussed, it depends a lot on how the compiler compiles the code, and the processor.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!