Home arrow C++ arrow Page 4 - Temporary Variables: Temporaries Are Not Necessarily Evil
C++

Temporary Variables: Temporaries Are Not Necessarily Evil


In earlier articles, we learned about the problems the passing of objects by value can cause in C++. Returning objects by value, on the other hand, is not necessarily evil. Jun Nakamura explains the finer points.

Author Info:
By: J. Nakamura
Rating: 5 stars5 stars5 stars5 stars5 stars / 9
October 03, 2005
TABLE OF CONTENTS:
  1. · Temporary Variables: Temporaries Are Not Necessarily Evil
  2. · Binding a reference to a temporary object
  3. · Death by Returned const Reference
  4. · It can be Good to Return by Value

print this article
SEARCH DEVARTICLES

Temporary Variables: Temporaries Are Not Necessarily Evil - It can be Good to Return by Value
(Page 4 of 4 )

We started this examination of temporary variables with looking at the extra overhead they can incur and how much more efficient the use of references can be. But the use of references brought its own dangers, like the possibility of returning handles to temporary objects that were constructed implicitly by the compiler.

So while references can come in very handy and bring us better efficiency, there are situations where we do not want to use them. One of these situations can be made clear by looking at the current state of our FindClosest function:

Enemy& FindClosest(list<Enemy> &enemies, Player const &player) {
 // cannot return an enemy when list is empty
 assert(!enemies.empty());

 list<Enemy>::iterator closest;
 float min_sqdistance=FLT_MAX;

 list<Enemy>::iterator nmeIt;
 for (nmeIt=enemies.begin(); nmeIt!=enemies.end(); nmeIt++) {
  
Vector3 nme2ply=player.GetPos() – nmeIt->GetPos();
  float sqdist=nme2ply.SquaredLength();
  if (sqdist < min_sqdistance) {
   closest=nmeIt;
   min_sqdistance=sqdist;
  }
 }
 return *closest;
}

Now we can justify the return of an Enemy by reference and the need to return the Enemy list by reference and the Player object by const reference. There is however a function used in there that returns its result by value rather than by reference:

class Vector3 {
 float mX, mY, mZ;
public:
      ...
      Vector3 const operator– (Vector3 const &rhs) const {
  return Vector3(mX-rhs.mX, mY-rhs.mY, mZ-rhs.mZ);
      }
      ...
};

As to why this function returns a Vector3 const, I would like to refer you to one of my other articles about Const Correctness.

To determine the vector from point A to point B, we subtract point A from point B. The positions of the enemies and the player are relative to the world’s origin, so each position can be considered to be a vector from this origin to reach that location.

As a side note, please observe that the Vector subtraction operator could have been declared the following way:

inline Vector3 const operator- (Vector3 const &lhs,
     Vector3 const &rhs) {
 return Vector3(lhs.x-rhs.x, lhs.y-rhs.y, lhs.z-rhs.z);
}

But this would have only been beneficial if we expected other objects to be able to implicitly be converted to Vector3 by the compiler. Since this is not the case (in a video game you actually want to avoid this because the Vector3 class is heavily used and temporary objects should be avoided as much as possible), it is fine to embed the subtraction operator in the class itself.

Returning to our main topic, when we compare the squared length of each resulting vector, we can determine which enemy is closest to the player.

The subtraction operator has to return a new object, because the operator is allowed to modify neither the left hand side nor the right hand side of the equation. Imagine what the effect would be if the call A = B – C would yield different results each time it was called subsequently! Nobody would want to use your math library.

The only way to circumvent the return of a new value would be to implement the subtract and assign operator:

Vector3& operator-=(Vector3 const &rhs)
{
 mX -= rhs.mX;  mY -= rhs.mY;  mZ -= rhs.mZ;
 return *this;
}

This will not allow us to construct a vector between an Enemy and the Player with this intuitive statement:

Vector3 nme2ply=player.GetPos() – nmeIt->GetPos();

But we would have to write this instead:

Vector3 nme2ply(player.GetPos());
nme2ply -= nmeIt->GetPos();

 

You might still argue that this is better, since the intuitive statement needs the construction and destruction of a temporary object, and the latter statement doesn’t. Luckily the C++ Standard tells us that we can help compilers to optimize the temporary variable away, which means that both statements can be as efficient, just not as intuitive.

In the next article we shall take a look at how we can facilitate Return Value Optimization and which other (though smaller) optimizations can be made to the FindClosest function.

At this point I hope that it is clear that the compiler can create a lot of unseen objects behind the scenes and that you understand why this is needed.

References might look like a secure rescue, but they too can turn on you in the most unexpected ways.

Just remember what is going on inside the language and how the compiler will deal with it (according to the C++ Standard) and you will be fine.

Know what you are doing so your code does what you think it should.


References

 [Meyers] – Scott Meyers

“Effective C++” – ISBN 0201924889

[Sutter] – Herb Sutter

“Exceptional C++” -  ISBN 0201615622

[Niebler] – Eric Niebler

“Conditional Love: FOREACH Redux”

http://www.artima.com/cppsource/foreach.html

[Kernighan] – Brian Kernighan (interview)

http://www-2.cs.cmu.edu/~mihaib/kernighan-interview/


DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware.

blog comments powered by Disqus
C++ ARTICLES

- Intel Threading Building Blocks
- Threading Building Blocks with C++
- Video Memory Programming in Text Mode
- More Tricks to Gain Speed in Programming Con...
- Easy and Efficient Programming for Contests
- Preparing For Programming Contests
- Programming Contests: Why Bother?
- Polymorphism in C++
- Overview of Virtual Functions
- Inheritance in C++
- Extending the Basic Streams in C++
- Using Stringstreams in C++
- Custom Stream Manipulation in C++
- General Stream Manipulation in C++
- Serialize Your Class into Streams in C++

Watch our Tech Videos 
Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 

Developer Shed Affiliates

 




© 2003-2017 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials