Reputation: 17271
Consider the following:
#include <vector>
using namespace std;
struct Vec2
{
float m_x;
float m_y;
};
vector<Vec2> myArray;
int main()
{
myArray.resize(100);
for (int i = 0; i < 100; ++i)
{
myArray[i].m_x = (float)(i);
myArray[i].m_y = (float)(i);
}
float* raw;
raw = reinterpret_cast<float*>(&(myArray[0]));
}
Is raw
guaranteed to have 200 contiguous floats with the correct values? That is, does the standard guarantee this?
EDIT: If the above is guaranteed, and if Vec2
has some functions (non-virtual) and a constructor, is the guarantee still there?
NOTE: I realize this is dangerous, in my particular case I have no choice as I am working with a 3rd party library.
Upvotes: 7
Views: 337
Reputation: 9199
I realize this is dangerous, in my particular case I have no choice as I am working with a 3rd party library.
You may add compile time check of structure size:
struct Vec2
{
float a;
float b;
};
int main()
{
int assert_s[ sizeof(Vec2) == 2*sizeof(float) ? 1 : -1 ];
}
It would increase your confidence of your approach (which is still unsafe due to reinterpret_cast, as mentioned).
raw = reinterpret_cast(&(myArray[0]));
ISO C++98 9.2/17:
A pointer to a POD struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. [ Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. —end note ]
And finally, runtime check of corresponding addresses would make such solution rather safe. It can be done during unit-tests or even at every start of program (on small test array).
Putting it all together:
#include <vector>
#include <cassert>
using namespace std;
struct Vec2
{
float a;
float b;
};
int main()
{
int assert_s[ sizeof(Vec2) == 2*sizeof(float) ? 1 : -1 ];
typedef vector<Vec2> Vector;
Vector v(32);
float *first=static_cast<float*>(static_cast<void*>(&v[0]));
for(Vector::size_type i,size=v.size();i!=size;++i)
{
assert((first+i*2) == (&(v[i].a)));
assert((first+i*2+1) == (&(v[i].b)));
}
assert(false != false);
}
Upvotes: 5
Reputation: 75150
No, this is not safe, because the compiler is free to insert padding between or after the two float
s in the structure, and so the float
s of the structure may not be contiguous.
If you still want to try it, you can add compile time checks to add more surety that it will work:
static_assert(sizeof(Vec2) == sizeof(float) * 2, "Vec2 struct is too big!");
static_assert(offsetof(Vec2, b) == sizeof(float), "Vec2::b at the wrong offset!");
Upvotes: 3
Reputation: 31685
The only guarantee that a reinterpret_cast
gives is, that you get the original object when you reinterpret_cast
the casted object back to the original data type.
Especially, raw
is not guaranteed to have 200 contiguous floats with the correct values.
Upvotes: -1