Strage problem with arrays
I'm writing a general purpose templated library for vector and matrix math. I want to be able to initialise a matrix with a 2D array. A matrix consists of an array of column vectors. A vector can take a pointer to a 1D array of initial values. I've tested that this works. But the similar constructor for the matrix causes a sigsegv. As far as I can see, all the array math is fine. From the stack trace, the value for initArray in Vec<4,float>::Vec is bogus. It should be pointing to the first element of one of the inner arrays of the 2D array passed into Mat<4,4,float>::Mat in main.
Here's a copy of the call stack at the time of the error:
Quote:
#0 00417483 Math::Vec<4u, float>::Vec(this=0x28fd30, initArray=0x3f800000) (E:/Documents/Prog/mathlib/vec.h:145)
#1 00417292 Math::Mat<4u, 4u, float>::Mat(this=0x28fe90, initArray=0x28fed0) (E:/Documents/Prog/mathlib/mat.h:80)
#2 00401505 main() (E:/Documents/Prog/mathlib/test_main.cpp:16)
And here is the relevent code from those functions:
main
Code:
typedef Math::Mat<4, 4> Mat4;
float mat_init[4][4] = { {1, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 1, 0},
{0, 0, 0, 1} };
Mat4 m1((const float**)mat_init); // Error here
Mat4 m2((const float**)mat_init);
Matrix constructor
Code:
template <unsigned int X, unsigned int Y, typename T>
Mat<X, Y, T>::Mat(const T** initArray) {
for (unsigned int i=0; i<X; ++i)
cols[i] = Vec<Y, T>(initArray[i]);
}
Vector contructor
Code:
template <unsigned int N, typename T>
Vec<N, T>::Vec(const T* initArray) {
for (unsigned int i=0; i<N; ++i)
els[i] = initArray[i];
}
And the interfaces for vectors and matrices
Code:
template <unsigned int N, typename T = float>
class Vec {
public:
Vec(); // Init elements to default value of type T
Vec(const T* initArray); // Init from array of N elements of type T
Vec(const T& initVal); // Init all elements to initVal
Vec(const Vec& copy);
~Vec();
Vec& operator= (const Vec& rhs);
T& operator[] (unsigned int i);
const T& operator[] (unsigned int i) const;
// Cast to any other type of vector (any dimensions, any element type)
template <unsigned int n, typename t>
operator Vec<n, t> () const;
private:
T els[N];
};
Code:
template <unsigned int X, unsigned int Y, typename T = float>
class Mat {
public:
Mat();
Mat(const T** initArray); // Init by array T [X][Y]
Mat(const Vec<Y, T>* initArray); // Init by array of column vectors
Mat(const Mat& copy);
~Mat();
Mat& operator= (const Mat& rhs);
Vec<Y, T>& operator[] (unsigned int);
const Vec<Y, T>& operator[] (unsigned int) const;
private:
// Store elements as X columns of Y elements of T
Vec<Y, T> cols[X];
};
Thanks.
Re: Strage problem with arrays
Quote:
Originally Posted by
CodeHippie
Mat4 m1((const float**)mat_init); // Error here
Mat4 m2((const float**)mat_init);
You've encountered an unintuitive but perfectly reasonable issue: a "2D array of T" is not the same as a T**. The fact that you needed an explicit cast to make the compile work should have been your first clue on this matter.
Basically, with a 2D array, the memory layout doesn't include any room for pointers. It doesn't need to; the dimensions are known at compile time, so the compiler can convert multi-dimensional accesses into 1D accesses at compile time.
With a T**, though, you've explicitly got to have an array of pointers. It's a different underlying assumption.
I would also point out that there are several good vector/matrix math libraries out there already: Boost.uBLAS, Eigen, MTL, etc.
Re: Strage problem with arrays
An array of arrays can be converted to a pointer to an array, but a pointer to an array is not a pointer to a pointer. You should cater for this by having a pointer to an array instead of a pointer to a pointer as the parameter.
Re: Strage problem with arrays
Right, of course! Thanks a lot man.
Re: Strage problem with arrays
If you really want to get confused, try and figure out why the compiler will refuse to implicitly convert a T** to a const T**.
Re: Strage problem with arrays
Quote:
Originally Posted by
Lindley
If you really want to get confused, try and figure out why the compiler will refuse to implicitly convert a T** to a const T**.
Or explicitly as a matter of fact.