Reputation: 109
If I want to define a Matrix
class in C++, for OpenGL rendering for example, the way I like to do it, and which also seems the most convenient, is to first define a Vector
class as such :
class vec3 {
double x;
double y;
double z;
[ ... ]
}
class vec4 {
double x;
double y;
double z;
double w;
[ ... ]
}
Now, as far as I understand, the values of x, y, z{, w}
are supposed to be contiguous in memory when I create a vec{3|4} (right ???).
If I then create my matrix as such :
class mat3 {
vec3 _m[3];
[ ... ]
}
class mat4 {
vec4 _m[4];
[ ... ]
}
Would the values of x, y, z{, w}
of each vector in the matrix class always be next to one another in memory ? If I give the adress of the first element to OpenGL, which reads the next 16 values in memory (for a 4x4 matrix), would it read the 16 values of the matrix in order, or could some other information from elsewhere in the program get in the way ?
Edit (29/Nov./2019) : Fixed a typo
Upvotes: 1
Views: 154
Reputation: 23691
The standard allows arbitrary padding, so technically whether the members are contiguous in memory is implementation-defined. I don't know of any implementation that does something unexpected for your case though, so you should be fine by just adding a static_assert(sizeof(vec3) == 3 * sizeof(double));
.
Similarly, accessing a bunch of members as if they were an array (i.e. via pointer arithmetic) in your code is undefined behavior by the standard, as there is no actual array object there. Now, if you give OpenGL this struct
which has the values in the right places there should be no problem (because your compiler presumably doesn't touch the OpenGL code and the OpenGL only cares that the bytes are what they should be).
But note that this is only "fine" for the scope of the course I would say. For actual production code, these assumptions are too flimsy and a more robust (but possibly slightly less convenient) approach should be preferred.
Upvotes: 0
Reputation: 179809
The robust solution is to start with a double[16]
. To the compiler, &vec3::y
is just a way to express the offset of y
, and you want that to be 1. You can achieve the same by writing
struct vec3 {
double* base;
double& x() { return *base; }
double& y() { return *(base+1); }
double& z() { return *(base+2); }
};
struct mat3 {
double values[9];
vec3 operator[](size_t s) { return vec3{values+3*s}; }
};
It's all inline, so the compiler can still calculate the offsets statically. There won't be a function call at runtime when you use y()
.
Upvotes: 0
Reputation: 238341
Would the values of x, y, z{, w} of each vector in the matrix class always be next to one another in memory ?
Probably not guaranteed to be so by the language, but probably will be contiguous in practice.
would it read the 16 values of the matrix
The behaviour of indexing over members is undefined in C++. The API probably written in C which may have different rules through.
There is a data structure that you can iterate over and is guaranteed to have 16 adjacent elements: array of 16 doubles.
Upvotes: 1