Sign in to follow this  

Using structs and arrays in UNIONS.

This topic is 4689 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

union
{
   struct 
   {
      float _11, _12, _13, _14;
      float _21, _22, _23, _24;
      float _31, _32, _33, _34;
      float _41, _42, _43, _44;
   };
   float m[4][4];
   float m_afEntry[16];
};

I have seen alot of people write code like this and I wonder if it is ok do use a union like this to access array elements multiple ways.

Share this post


Link to post
Share on other sites
it is, but it allows the programmer to access those 16 floats in the most appropriate way, without any overhead. sure, it could still be done with just an array of floats, but that would cause ugly (and possibly confusing) code.

Share this post


Link to post
Share on other sites
This is safe, as long as you don't put a class with nondefault constructors or destructor in such an union.

This is because the data can only be constructed or destructed once, but there is a "default" way and a "nondefault" way.

Stupid example:


union error {
class A1 { public: int * x; ~A1( delete x ); } a;
class A2 { public: int * x; ~A2( free(x) ); } b;
};





What happens when such an object is destroyed?

Share this post


Link to post
Share on other sites
anonymous struct/classess are non-standard compliant, compilers support it as language extension only so its not portable code, for much better, safer and standard compliant alternative to unions look at this thread.

Share this post


Link to post
Share on other sites
Quote:
Original post by iMalc
It's just syntactical sugar. There's no real need for it.
It's like how eskimos have 200 different words for snow.


That's true but it can make an unreadable algorithm very very readable. It is also very hard to code some algorithms if you only use a flat array.

Share this post


Link to post
Share on other sites
Hey don't get me wrong, I never said we shouldn't have unions or anything, I just disagree with the over usage of them in this particular case. I just don't see the need to be able to access each matrix entry in three different ways, in this case.

The first way in particular is not so good, particularly because the way those variables are named, _12 is not the same as m[1][2], which can lead to various o.b.o errors. Not to mention if your're reading through 3 different functions in a row and they each use a different way of accessing the data, the lack of consistency takes its toll on the reader.

Worse still would be one function, accessing members in more than one way i.e.
mtx.m[1][2] = 1;
mtx.m_afeEntry[6] = 2;
mtx._23 = 3;
It can thus also make a readable algorithm very unreadable. [totally]
(opposite of what qesbit said)

These are exactly the kinds of things the OP was probably worrying about, and as shown the concern is warranted. You just have to hope that no-one misuses your data type like that. It is of course perfectly legal though.


btw, I wouldn really only loosely apply the term 'abstraction' here myself. The use of a union in itself isn't really hiding, or seperation you from, any implementation details.

Share this post


Link to post
Share on other sites
A bit offtopic, but related in a way...
Quote:
Original post by snk_kid
anonymous struct/classess are non-standard compliant, compilers support it as language extension only so its not portable code, for much better, safer and standard compliant alternative to unions look at this thread.
I looked at that thread and had a little try at making a row vector (it's a bit hacky though...).
#include <cstddef>
#include <iostream>

template< typename T >
struct Vector4 {

typedef size_t size_type;

private:

typedef T Vector4<T>::* const vec[4];

static const vec v;

public:

T x, y, z, w;

Vector4(T _x = 0, T _y = 0, T _z = 0, T _w = 0):
x(_x), y(_y), z(_z), w(_w) {}

const T& operator[](size_type i) const {
return this->*v[i];
}

T& operator[](size_type i) {
return this->*v[i];
}

};
template< typename T >
const typename Vector4<T>::vec Vector4<T>::v = { &Vector4<T>::x, &Vector4<T>::y, &Vector4<T>::z, &Vector4<T>::w };


// row vector from a Matrix4...
template< typename T >
struct RowVector4 {

typedef size_t size_type;

private:

typedef T Vector4<T>::* const offset[4];

static const offset o;

public:

// pointer to the first element in the row
Vector4<T>* base;

RowVector4( Vector4<T>& _base ):
base( &_base ) {}

const T& operator[](size_type i) const {
return base->*o[i];
}

T& operator[](size_type i) {
return base->*o[i];
}

};

template< typename T >
struct matrix4 {

typedef size_t size_type;

private:

typedef Vector4<T> matrix4::* const mat[4];

static const mat a;

typedef T Vector4<T>::* const off;

public:

Vector4<T> i, j, k, l;

matrix4(const Vector4<T>& _i = Vector4<T>(),
const Vector4<T>& _j = Vector4<T>(),
const Vector4<T>& _k = Vector4<T>(),
const Vector4<T>& _l = Vector4<T>())
: i(_i), j(_j), k(_k), l(_l) {}

const Vector4<T>& operator[](size_type i) const {
return this->*a[i];
}

Vector4<T>& operator[](size_type i) {
return this->*a[i];
}


RowVector4<T> row( size_type i ) {
return RowVector4<T>( reinterpret_cast< Vector4<T>& >( this->i[i] ) );
}

};

template< typename T >
const typename matrix4<T>::mat matrix4<T>::a = { &matrix4<T>::i, &matrix4<T>::j, &matrix4<T>::k, &matrix4<T>::l };


template< typename T, typename U >
T const hack_cast( U const old ) {
return reinterpret_cast< T const >( old );
};

template< typename T >
const typename RowVector4<T>::offset RowVector4<T>::o = { hack_cast<T Vector4<T>::*>( &matrix4<T>::i ), hack_cast<T Vector4<T>::*>( &matrix4<T>::j ), hack_cast<T Vector4<T>::*>( &matrix4<T>::k ), hack_cast<T Vector4<T>::*>( &matrix4<T>::l ) };


matrix4< int > m;

void col() {
for ( int i = 0; i < 4; ++i ) {
for ( int j = 0; j < 4; ++j ) {
std::cout << "m[" << i << "][" << j << "]: " << m[i][j] << '\n';
}
}
};

void row() {
for ( int i = 0; i < 4; ++i ) {
for ( int j = 0; j < 4; ++j ) {
std::cout << "m.row(" << i << ")[" << j << "]: " << m.row( i )[j] << '\n';
}
}
}

int main() {


for ( int i = 0; i < 4; ++i ){
for ( int j = 0; j < 4; ++j ) {
m[i][j] = j;
}
}

row();
col();

system("PAUSE");
return 0;
}


[Edited by - lucky_monkey on February 12, 2005 10:25:48 PM]

Share this post


Link to post
Share on other sites

This topic is 4689 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this