Inquiry about class variable declarations in C++

前端 未结 6 1170
悲&欢浪女
悲&欢浪女 2021-01-19 00:43

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),         


        
相关标签:
6条回答
  • 2021-01-19 01:25

    The compiler has some flexibility in how it lays out the memory within a struct. The struct will never overlap another data structure, but it can inject unused space between elements. In the struct you give, some compilers might choose to add 4 bytes of extra space between z and data so that the data pointer can be aligned. Most compilers provide a way of packing everything tightly.

    EDIT: There's no guarantee that the compiler will choose to pack x, y, and z tightly, but in practice they will be packed well because they are the first elements of the struct and because they're a power of two in size.

    0 讨论(0)
  • 2021-01-19 01:29

    Do something like this:

    float data[3];
    float& x, y, z;
    
        Vector3D() : x(data[0]), y (data[1]), z(data[2]) { data [0] = data [1] = data [2] = 0;}
    
    0 讨论(0)
  • 2021-01-19 01:33

    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.

    0 讨论(0)
  • 2021-01-19 01:34

    or you can have an operator[] overload

    float operator[](int idx)
    {
     switch (idx)
    {
    case 0:
      return x;
    case 1:
      return y;
    case 2:
     return z;
    }
    assert (false);
    }
    
    0 讨论(0)
  • 2021-01-19 01:37

    Your solution is not valid, but if you can ensure (or know) that your compiler will "do the right thing" (in particular by controlling padding between the x, y and z elements) you will be ok. In this case though I'd remove the data member altogether and use operator[].

    I've seen something like this used on occasion. It runs into exactly the same issues, but does save you storing that data pointer, and allows for a nicer v[0] syntax rather than v.data[0].

    class Vector3D
    {
        public:
    
        float x, y, z;
        float& operator[](int i) { return *(&x+i); }
        const float& operator[](int i) const { return *(&x+i); }
    
        Vector3D() : x(0.0), y(0.0), z(0.0) {}
    }
    

    EDIT: Prompted by ildjam heres a compliant version using accessors rather than members, that is similar.

    class Vector3D
    {
        public:
          float& operator[](int i) { return v[i]; }
          const float& operator[](int i) const { return v[i]; }
    
          float& x() { return v[0]; }
          float  x() const { return v[0]; }
          float& y() { return v[1]; }
          float  y() const { return v[1]; }
          float& z() { return v[2]; }
          float  z() const { return v[2]; }
    
          Vector3D() : v() {}
        private:    
          float v[3];
    };
    
    0 讨论(0)
  • 2021-01-19 01:39

    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.

    0 讨论(0)
提交回复
热议问题