Jump to content
  • Advertisement
Sign in to follow this  
karwosts

C++: Should I use a reference member here?

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

I'm working on a project, and in my project I've created a class Vector3. Very simplified, it looks something like this:
class Vector3  
{
public:
        ...(lots of member functions)...
	float i;
	float j;
	float k;
};

Now I've happily used this for a while, but I come to a point where I would like the ability to cast this object to a float*, which would just be a float of three values representing i,j, and k. I realize now that I probably need to have i,j,k stored as a float[3] array internally so I can return a pointer to it. Problem is I already have 500 references to vector.i, etc strewn about my project, and I kind of like having the ability to be able to reference the values that way. My first thought would be to store the data in a private float[3], and then let i,j,k be references to those values:
class Vector3  
{
public:
        ...(lots of member functions)...
	float& i;
	float& j;
	float& k;
private:
	float data[3];
};

But now I'm thinking that this is unnecessarily doubling the size of my class (now holds three pointers and three floats, not sure if references take up memory though). Also now I think I have to define a custom copy and assignment constructor because the default constructor no longer works, and this is starting to feel a little more complicated than it should. I'm wondering too if this will be slower than before if there is some cost with dereferencing the references every time? Basically I'm wondering if there is some construct I should use to tell the program: when I say vector.i, I really want vector.data[0] Is using the references the right way to go? Is there some other method that would be better? Thanks for any input!

Share this post


Link to post
Share on other sites
Advertisement
Try using a union.

Example:


class Vector {
public:
union {
struct {
float x,y,z;
}
float data[3];
};
};

Vector v;
v.x = 1;
v.y = 2;
v.z = 3;
assert(v.data[0]==1 && v.data[1]==2 && v.data[2]==3);

Share this post


Link to post
Share on other sites
Just to be aware that such anonymous types aren't standard C++. Indeed, pasting your code into codepad.org suggests that GCC rejects it (at least with whatever compile flags they are using).

Share this post


Link to post
Share on other sites
Thanks to both of you guys. Union was a good idea, I rarely have used them and I wouldn't have thought of it.

For now I'm going ahead with anonymous union / named struct. I like to be able to access elements by name and by array, and it only took me 5 minutes to update all of the references.

However I tried codepad again with this and it still doesn't like it. The code is working fine in MSVC++ (although I know that can be non-standard).

I believe anonymous union is legal in C++, is there something else that is wrong with this (non-standard-complient)?

Codepad

I named my struct elem, but when I reference v.elem.x it errors:

Line 12: error: expected constructor, destructor, or type conversion before '.' token

Share this post


Link to post
Share on other sites
Quote:
Original post by karwosts
I believe anonymous union is legal in C++, is there something else that is wrong with this (non-standard-complient)?
Anonymous unions are allowed; anonymous structs are not. By default, however, all major C++ compilers support them.

Share this post


Link to post
Share on other sites
If it were me, I would just go ahead and return &i for your float*. (And ijk for a vector? Wtf?) Appropriate use of pragma should control the structure layout appropriately, and a BOOST_STATIC_ASSERT can seal the deal.

Share this post


Link to post
Share on other sites
I'm not sure if this would help or not, but my suggestion would be to create a member operator[] (don't forget you need both const and non-const versions), that returns either i,j or k, depending on the subscript. So something like the following:



// Vector3.h

class Vector3
{
public:
// stuff

float & operator[](const int subscript);
const float & operator[](const int subscript) const;

float i;
float j;
float k;
}

// Vector3.cpp

float & Vector3::operator[](const int subscript)
{
switch(subscript)
{
case 0:
return i;
break;
case 1:
return j;
break;
case 2:
return k;
break;
default:
// Handle out-of-bounds error here
}
}

const float & Vector3::operator[](const int subscript) const
{
switch(subscript)
{
case 0:
return i;
break;
case 1:
return j;
break;
case 2:
return k;
break;
default:
// Handle out-of-bounds error here
}
}

int main()
{
Vector3 v;
v.i = 3;
v[0] = 2; // v.i = 2

return 0;
}



I didn't test it or anything, but I don't see why it wouldn't work. It would prevent bloating your class by the size of three more floats, allow your current code to work and look cleaner than v.data[]

Share this post


Link to post
Share on other sites
Quote:

If it were me, I would just go ahead and return &i for your float*. Appropriate use of pragma should control the structure layout appropriately


I wasn't aware that those floats are guaranteed to be contiguous in memory, but rather at the mercy of the compiler. What pragma are you suggesting? That sounds like something I would expect to work 99 times out of 100 but that I couldn't guarantee.

Quote:
(And ijk for a vector? Wtf?)

Isn't this pretty common notation?


Thanks for the suggestion Raislin, but at this time I wasn't really looking for a way to access the elements with array notation. I just need an array of 3 floats I can send to OpenGL API, while I was hoping to maintain compatibility with my older code that uses ijk notation.

Thanks again, learning some new things today :)

Share this post


Link to post
Share on other sites
Sorry but I have to lol, all you want to do is 'cast' your vector class into an array of floats right?

So then why has noone offered this solution:
#include <iostream>

class Vector3
{
public:
float x, y, z;
Vector3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}

operator float *( ); // add this declaration
operator const float *( ) const; // add this declaration
};

Vector3::operator float *( ) // add this definition with 'x' swaped for 'i'
{
return &x;
}

Vector3::operator const float *( ) const // add this definition with 'x' swaped for 'i'
{
return &x;
}

void Print(float arr[], unsigned int size)
{
for (unsigned int i = 0; i < size; ++i)
std::cout << arr << ' ';
std::cout << std::endl;
}

int main(int argc, char** argv)
{
Vector3 Vec(1.4f, 10.51f, 3.3f);
Print(Vec, 3);
return 0;
}







Theres a working example program of how you can construct your Vector class so that you can cast it to a float* which can be indexed like an array and passed to those OpenGL (and Direct3D) functions.

I use this method for my Matrix, Vector, Color and other classes and i believe ive also seen Microsoft implement a casting operator for there D3DXMATRIX class.

PS: No, (i,j,k) is not standard notation for a vector, it is (x, y, z, w) depending on how many dimensions your vector class covers (four is usually the maximum as for as games go, 'w' has something to do with homogenous coordinates and matrices, im not sure i didnt really read into it that much).

[Edited by - CodeCriminal on March 6, 2010 7:18:59 PM]

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.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!