2

Background

I am studying Math related to Game Engines from the book Foundations of Game Engine Development, Volume 1: Mathematics.
The implementation of operator overloads seemed different than the way I would have done it had I not been reading this book and looking at its examples. I wanted to see if the way the author coded it up had performance implications. Searching for the answer to this question was difficult and I could only find other questions about inlining that had nothing to do with comparing these specific styles of declaring operator overloads.

The Example

Vec3.h Version 1

class Vec3
{
public:

    float x;
    float y;
    float z;

    Vec3(float x, float y, float z);

    inline Vec3 operator+(const Vec3& rval) const
    {
        return Vec3(this->x+rval.x, this->y+rval.y, this->z+rval.z);
    }
};

vs

Vec3.h Version 2

class Vec3
{
public:
    float x;
    float y;
    float z;
    Vec3(float x, float y, float z);

};
inline Vec3 operator+(const Vec3& lval, const Vec3& rval)
{
    return Vec3(lval.x+rval.x, lval.y+rval.y, lval.z+rval.z);
}

The Question

Version 1 is how I would have implemented the operator+ overload. It seems like the C++ way, making the operator a method of the class.

However, I see throughout the book that the author continues to use version 2 whenever declaring overloads. He declares them outside of the class definition and uses 2 arguments (lval and rval) rather than the implicit this(lval) and right hand argument(rval)

If you try to implement both, understandably there is a compiler error saying it's ambiguous. Which is exactly why I am here to ask this question. To me, it's equivalent and I would rather not have a function sitting in global space, so I would implement version 1.

However, I figured there might be a performance reason for implementing version 2. Maybe inlining is easier for the compiler, or it executes faster for some arcane reason that the author does not mention.

Another idea I had is that perhaps inline is actually functioning more like "static" in this case. I have read elsewhere that inline is pretty much ignored by the compiler anyways because it's going to try to inline it anyway.

When doing

Vec3 v1(1,2,3);
Vec3 v2(1,2,3);
Vec3 v3 = v2-v1;

which performs better? Or, is this just more of a preference thing? Additionally, would it behave differently based on the C++ version? (tagged C++11, 14, and 17 for that reason)

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Dean Knight
  • 660
  • 6
  • 17
  • 5
    Immortal and always right answer to questions about performance is - measure it because modern computers are too complicated for us to be able say anything a priori – bartop Jul 10 '20 at 07:38
  • 3
    this decision is based on what makes a good interface, not so much on performance. The general recommendation is to prefer free functions over members, see eg https://stackoverflow.com/questions/21028773/free-function-versus-member-function – 463035818_is_not_an_ai Jul 10 '20 at 07:43
  • Maybe the author explains the code in the book. So why not try to read it to find the answer? – MrSmith42 Jul 10 '20 at 07:46
  • Yeah, I scanned through it searching using multiple key words and it isnt mentioned at all MrSmith42. However, the comment above yours makes it quite clear that its a more effective way of coding. Its probably a coding standard thing which makes sense if you are developing deep engine stuff that needs to be solid. Thanks idclev, I am taking a good look at your link to really understand why version 2 styling is more effective for coding. Seems straight forward enough. – Dean Knight Jul 10 '20 at 07:48
  • 3
    Generally speaking, if I can have a free function over a member function, I tend to favor the free function alternative. It may sound counter-intuitive but doing so actually enhances encapsulation. With regard to "performance" concerns, @bartop is right, you would need to compare the actual output. A quick run shows they are equivalent: https://godbolt.org/z/43szce – Rerito Jul 10 '20 at 07:49
  • Thanks Rerito, been out of the coding game for a while and just never realized how free functions effected encapsulation. – Dean Knight Jul 10 '20 at 07:52
  • 2
    In version 1, the `inline` is superfluous; functions defined inside a class definition are implicitly `inline`. (`inline` has nothing to do with inlining of function calls.) – molbdnilo Jul 10 '20 at 07:58
  • I have gone down the rabbit hole with that link @idclev463035818 I think I have a firm grasp now why that styling is preferable. In this case because we are working with a lower level datatype that is using convenient public data it does not really seem to have a big impact on encapsulation. Since the free function operator+ can directly access the data. However, its good coding practice to use the free function because if this was a more complex class, private data would be encapsulated from the free function making things more robust. Its a good habit to have and I see why now. Thanks – Dean Knight Jul 10 '20 at 08:31
  • @idclev463035818 If you take your comment and make it an answer, I can select it as the answer so this question can be considered solved. – Dean Knight Jul 10 '20 at 08:32
  • @DeanKnight actually the encapsulation part isnt what I find most convincing. [Here](http://www.gotw.ca/gotw/084.htm) Herb brings up more arguments, eg making everything member makes the class more difficult to extend. Everybody can add a free function but to add a member you need to change the class definition – 463035818_is_not_an_ai Jul 10 '20 at 08:33
  • 1
    I was considering to flag as duplicate, if you are fine with that... – 463035818_is_not_an_ai Jul 10 '20 at 08:34
  • Sounds good to me. It totally is a duplicate. Due to it being game engine material my mind went immediately to performance due to so much of the book being about that. Embarrassing that I didn't think about it being more of a "software engineering" thing. – Dean Knight Jul 10 '20 at 08:36
  • And yes, being able to extend a class easily like that makes a lot of sense especially when working on a game engine with many other programmers who may need specific little bits of functionality but you do not want to risk introducing bugs by making changes to the class definition. – Dean Knight Jul 10 '20 at 08:37

0 Answers0