5

I currently have a 4x4 matrix class in C++ and I store each value as a float:

Matrix4d::Matrix4d(const float& m00, const float& m01, const float& m02, const float& m03,
                   const float& m10, const float& m11, const float& m12, const float& m13,
                   const float& m20, const float& m21, const float& m22, const float& m23,
                   const float& m30, const float& m31, const float& m32, const float& m33)
{
    _m00 = m00;
    _m01 = m01;
    _m02 = m02;
    _m03 = m03;
    _m10 = m10;
    _m11 = m11;
    _m12 = m12;
    _m13 = m13;
    _m20 = m20;
    _m21 = m21;
    _m22 = m22;
    _m23 = m23;
    _m30 = m30;
    _m31 = m31;
    _m32 = m32;
    _m33 = m33;
}

My question is, how can I return a float array of this data? I have no problem creating the array in the class for example:

float arrayToReturn[16] = { m00, m01, m02, m03, ... m33 };

However I can not return this value from the class. I've read about returning a pointer to the array, but have had no luck with it.

0

5 Answers 5

4
  1. Don't pass floats by const reference, pass them by value.

  2. I assume you want to return the array so you can do indexing? Then don't return an array from you matrix class. Instead, overload the [] operator or something.

  3. Also, I wouldn't use 16 member variables but one array instead. Makes indexing a lot easier.

Here is how I would probably do it:

class Matrix4d
{
    float matrix[4][4];

public:

    Matrix4d(float m00, float m01, float m02, float m03,
             float m10, float m11, float m12, float m13,
             float m20, float m21, float m22, float m23,
             float m30, float m31, float m32, float m33)
    {
        matrix[0][0] = m00;
        matrix[0][1] = m01;
        matrix[0][2] = m02;
        matrix[0][3] = m03;
        matrix[1][0] = m10;
        matrix[1][1] = m11;
        matrix[1][2] = m12;
        matrix[1][3] = m13;
        matrix[2][0] = m20;
        matrix[2][1] = m21;
        matrix[2][2] = m22;
        matrix[2][3] = m23;
        matrix[3][0] = m30;
        matrix[3][1] = m31;
        matrix[3][2] = m32;
        matrix[3][3] = m33;
    }

    float* operator[](int i)
    {
        return matrix[i];
    }

    const float* operator[](int i) const
    {
        return matrix[i];
    }
};

int main()
{
    Matrix4d test(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 16);
    test[3][2] = 15;
}
Sign up to request clarification or add additional context in comments.

6 Comments

+1, especially for the array suggestion. @james: along these lines, unless you're writing a high performance app (such as for 3-D game or for crypto), consider using the vector class. It implements much you'd otherwise have to.
Thanks for the input, I'm creating a 3d game for a mobile device! The only reason I made my own matrix class was so I could return a 1d array and call glMultMatrixf, but also so I could calculate my matrix equations using it. It's running fine now! @Fred Why shouldn't I pass floats by const?
Because the amount of information necessary to pass a reference to a float is never smaller than a float itself, and the additional level of indirection can hurt performance. Passing a float by const reference does not buy you anything.
Ok, thanks for that. I was only doing it from what I've been taught at uni!
I agree 2D arrays are probably a better way of storing it, thanks.
|
3

This would work if your internal array looked like float array[4][4]:

float** Matrix4d::getMatrix();

If your internal array was a one-dimensional array:

float* Matrix4d::getMatrix();

But both cases expose the internal workings of your class to the outside world, with makes your code less safe and harder to maintain.

It would be better to create a copy constructor, a () operator, and an assignment operator for your Matrix4d class and just pass that around. You'd be less likely to have runtime errors due to bad memory management or data corruption.

Your () operator would look like this:

float& operator()( unsigned int xIndex, unsigned int yIndex )
{
  //return the right attribute
}

You would call it like this for setting values:

aMatrix(0,0) = 2.0;

or this for retrieving:

float attributeCopy = aMatrix(0,0);

It works both ways.

EDIT: Forgot that the [] operator only took one argument. Changed the operator to the () operator a.k.a the functional operator.

9 Comments

That operator doesn't exist in the C++ language.
No, that doesn't work. a[x, 0] will be equivalent to a[0] (if x has not overloaded its comma operator). I'm also unsure about your float** way: It will definitely not work to return arrayToReturn; with that function declaration.
Yes. The float** would work only if your internal array was a 2D array
Updated the answer to clarify return values of the getMatrix function.
@thebretness, no doing float x[4][4]; return x; would definitely not work with that function declaration. You need to change the return type to float(*)[4]. For example identity<float[4]>::type *getMatrix();.
|
2

You can use a union to describe your class.

union
{
    struct
    {
       float _m00;
       float _m01;
       ...
    };
    float _m[16];
};

You can then return _m.

also getting cols can be useful so:

union
{
    struct
    {
       float _m00;
       float _m01;
       ...
    };
    float _m[4*4];
    float _cols[4][4];
};

1 Comment

+1. While I wouldn't recommend this for C++ (there are more user friendly and intuitive ways to accomplish this), for C this is a great solution.
1

Three options I can think of.

The first is return a std::vector rather than an array. The user can always get pointer to the internal array by &v[0].

std::vector<float> Matric4d::getData() { 
  std::vector<float> d(16); 
  d[0]=_m00; 
  ... 
  return d;
}

The second is return a boost::array. (I think there's a tr1::array from the upcoming C++0x standard if your compiler supports something like that) Again its easy to get to the internal array.

The third is the hackiest but may best if you need speed. If you're storing your floats contiguously you could just return a pointer to the first entry. (Note you need to be careful about the details of your class otherwise you end up with "undefined behaviour". However, many/most/all compilers will still "do the right thing" anyway.) Oh and you need to be careful as the pointer will only be valid while the matrix still exists.

float * Matrix4d::getData() { return &_m00; }

1 Comment

Indeed. Array indexing is just pointer arithmetic in disguise. Doing pointer arithmetic on a pointer pointing to a single element (as opposed to an array) is undefined behavior.
1

Just access the address of the first element.

inline float* asArray {
  return &_m00 ;
}

You can treat any struct as an array.

Matrix4d matrix ;
// init with values..

functionThatExpectsArrayOfFloat( &matrix._m00 ) ;

2 Comments

Thanks for the input. I haven't looked at this project for 2 years but I will use this in the future :D Thanks
There's already a pretty good answer up there, which came 2 years before you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.