Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inquiry about class variable declarations in C++

I have a class to represent a 3D vector of floats:

class Vector3D
{
    public:

    float x, y, z;
    float * const data;

    Vector3D() : x(0.0), y(0.0), z(0.0), data(&x) {}
}

My question is: are x, y, and z going to be allocated sequentially in memory such that I can assign the address of x to data and later use the subscript operator on data to access the vector components as an array?

For example, sometimes I may want to access the vector components directly:

Vector3D vec;
vec.x = 42.0;
vec.y = 42.0;
vec.z = 42.0;

And sometimes I may want to access them by offset:

Vector3D vec;
for (int i = 3; i--; )
    vec.data[i] = 42.0;

Will the second example have the same effect as the first one, or do I run the risk of overwriting memory other than the x, y, and z floats?

like image 396
milesleft Avatar asked Jun 07 '11 23:06

milesleft


2 Answers

No, this is undefined behaviour, for two reasons:

  • Firstly for the padding issues that everyone else has mentioned.
  • Secondly, even if things are padded correctly, it is not valid to dereference a pointer with an offset that would take it beyond the bounds of what it's pointing to. The compiler is free to assume this, and make optimisations that would lead to undefined behaviour if you violate it.

However, the following would be valid:

class Vector3D
{
public:
    std::array<float,3> data;
    float &x, &y, &z;

    Vector3D() : data(), x(data[0]), y(data[1]), z(data[2]) { }
    Vector3D& operator =(Vector3D const& rhs) { data = rhs.data; return *this; }
};

std::array is new to C++0x, and is basically equivalent to boost::array. If you don't want C++0x or Boost, you could use a std::vector (and change the initializer to data(3)), although that's a much more heavyweight solution, its size could be modified from the outside world, and if it is, then the result would result be UB.

like image 65
Oliver Charlesworth Avatar answered Sep 30 '22 23:09

Oliver Charlesworth


Yes. This class is layout-compatible standard-layout, because:

  • You have no virtual functions.
  • All data members are in a single access specifier block (the public:)

Because of this, it's guaranteed to be laid out sequentially just like a C structure. This is what allows you to read and write file headers as structures.

like image 31
Ben Voigt Avatar answered Oct 01 '22 00:10

Ben Voigt