# Is this a valid usage for unions?

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

## Recommended Posts

Hello all,

recently I decided to discard my hand-written math library code and use the GLM library.

Because I want to make it "feel" like my own code need some thin wrapper around it. Because performance matters I don't want to
write the wrapper using inheritance like this:

 class Vector3 : public glm::dvec3 { }; 

Now I have the idea to use a union and write code like this:

 union Vector3 { public: Vector3(double x, double y, double z) : v(x, y, z) { } double x, y, z; private: glm::dvec3 v; }; 

##### Share on other sites
Access to members of a virtual base and calling virtual functions will typically result in a small performance penalty, but in the kind of inheritance you've shown, there will be none.

The doubles x, y and z in your union all occupy the same memory location. Presumably that's not intended.

I also suspect that you're heading down the road of type punning through the union, which strictly speaking is illegal, though some compilers explicitly support it. Take care.

My recommendation: typedef glm::dvec3 Vector3;

##### Share on other sites

of course  double x, y, z  does not work.

So I have to use something like this:
 union Vector3 { public: Vector3(double x, double y, double z) : v(x, y, z) { } inline double x() { return d[0]; } inline double y() { return d[1]; } inline double z() { return d[2]; } private: double d[3]; glm::dvec3 v; }; 

Actually I wanted to avoid the method calls for accessing the data members...

Are compilers smart enough to optimize this code (this post) so that it performs as fast as the first one (previous post)?

##### Share on other sites
Using  typedef glm::dvec3 Vector3  was my first idea BUT I want things like the cross product to be used as member functions. GLM implements them as
normal functions taking the two vectors as parameters.

But when the inheritance I have suggested does not have any performance penalties I will go that way. Edited by madRenEGadE

##### Share on other sites

GLM implements them as normal functions taking the two vectors as parameters.

That makes perfect sense I'd say; as a cross product is a pure function, to have it appear to "act upon" any particular vector would be strange. A cross product also has no need to access or manipulate the (non-existent) private state of a vector. Free functions also play nicer with generic code, FWIW.

##### Share on other sites
Ok for the cross product it makes sense. But normalize?

##### Share on other sites
Same reasoning (IMO). One input, one output, no dependency on the private state. Edited by edd²

##### Share on other sites
I don't think you want to be using a union here, it might work one way or another, but I can't see this as being considered good practice

I'd just go with the inheritance if you want to add some of your own functions, I can assure you that the "performance penalty" that could possibly be introduced by it will be least of your worries in the end. Otherwise go for the typedef, clean and simple.

By the way, only worry about optimizing these little things like inheritance overhead if they actually pose a problem, and in this case it'll probably never become a problem. In the end there will be loads of better candidates for optimization before you should even consider looking at overhead caused by language mechanisms.

##### Share on other sites

Same reasoning (IMO). One input, one output, no dependency on the private state.

I think you are right, at least if normalize creates a new vector. But when I really want to normalize the instance normalize is invoked on, it needs access to the state. But maybe that is not the problem as the state is public...

I don't think you want to be using a union here, it might work one way or another, but I can't see this as being considered good practice

"Good practice" is enough of a reason for me to not use unions for this

##### Share on other sites
You might want to look at the coding style for the rest of your code (I assume you're writing a game?) and adapt to what fits best with that so you can save yourself the headache of having to keep different coding styles in mind later on

If there's no other code to speak of and if you're comfortable with it I'd say go with edd's suggestion. Edited by Radikalizm

##### Share on other sites
Member functions would fit better to the rest of my code. But for the free functions I would rather like to use something like Vector3::normalize(v). So I would need to
use inheritance + static methods?! The typedefs would also be fine but Is it possible to typedef the free functions of glm (never done something like that)?

I think of:
 namespace Math { typedef glm::dvec3 Vector3; typedef glm::normalize Normalize; }; 

Maybe I could just write inline functions for my desired "renaming":

 namespace Math { inline Vector3 Normalize(const Vector3& v) { return glm::normalize(v); } }  Edited by madRenEGadE

##### Share on other sites
The typedef keyword is for use with datatypes only

Inlining would work, but IMO you're going to end up doing lots of work wrapping all the functions provided by glm without any real purpose

##### Share on other sites

Inlining would work, but IMO you're going to end up doing lots of work wrapping all the functions provided by glm without any real purpose

The purpose for me is that all my code looks consistent and that I could change the math library later on. And fortunately is is not that much work because I would just wrap the functions I actually need.

Thanks to both of you for the help

##### Share on other sites
Good OOP practice prefers to minimize interfaces that have access to internal state (including 'friend' functions or 'friend' classes), and prefers non-member, non-friend functions located in the same namespace--because of Koenig Lookup, these functions are still effectively a part of the class interface, but better promote encapsulation.

True member functions should be used to provide the minimum necessary interface needed to implement higher-level interface functions or when the object is itself modified by the operation. Using these member functions should be the preferred means of implementing higher-level functionality through non-member, non-friend functions, but non-member friend functions can be used in cases when a function requires non-modifying access to object internals (though this usually indicates that your "true member" interface is lacking) using a const reference to the object. Edited by Ravyne

##### Share on other sites
Really good explanation!!!

So best choice for e.g vector normalization would be a free function in the Math namespace which takes a const reference to a vector and to have a member function
which does not take parameters but normalizes the vector instance itself?

##### Share on other sites

Actually I wanted to avoid the method calls for accessing the data members...

Are compilers smart enough to optimize this code (this post) so that it performs as fast as the first one (previous post)?

Using  typedef glm::dvec3 Vector3  was my first idea BUT I want things like the cross product to be used as member functions. GLM implements them as
normal functions taking the two vectors as parameters.

But when the inheritance I have suggested does not have any performance penalties I will go that way.

Yes, if you inherit a value type, and always use the object via the derived class and retain the POD-likeness of the object (no custom ctors/dtors/assignments or copy-ctors), you will not have to use a virtual dtor, and there will be no performance penalties.

If you are interested in having a look at another library which does give you accesses to vector .x/.y/.z without function calls, and has .Cross() as a member function (but also as a freestanding function), see my MathGeoLib library. The float3 class reference is here.

##### Share on other sites
I'd do it something like this (syntax may not be exact since I don't have a compiler in front of me):

 namespace math { class vector { ... public: vector& normalized() { float inverse_length = 1 / this.length(); this.x *= inverse_length; this.y *= inverse_length; this.z *= inverse_length; return *this; } ... }; vector& normalized_copy(vector to_normalize) { // notice I take this by value return to_normalize.normalized(); } } 

Here, the non-member, non-friend function takes the vector by value and then uses the member function normalize() to do the work. This pattern of passing in by value, modifying that object, and returning it modified and by reference enables the Return Value Optimization (RVO), so it not only re-uses the member implementation, but is efficient as well. RVO basically eliminates redundant copies of the object. Using a similar pattern, you can implement binary +, -, *, / and other operators as non-member, non-friend functions by re-using the unary member operators for +=, -=, *=, /=, etc. Edited by Ravyne