查询C ++中的类变量声明

时间:2011-06-07 23:35:07

标签: c++ arrays variables memory-address subscript

我有一个类来表示浮动的3D矢量:

class Vector3D
{
    public:

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

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

我的问题是:x,y和z是否会在内存中顺序分配,以便我可以将x的地址分配给数据,然后使用数据上的下标运算符来作为数组访问矢量分量?< / p>

例如,有时我可能想直接访问矢量组件:

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

有时我可能想通过偏移来访问它们:

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

第二个示例是否与第一个示例具有相同的效果,或者我是否存在覆盖x,y和z浮点数以外的内存的风险?

6 个答案:

答案 0 :(得分:6)

不,这是未定义的行为,原因有两个:

  • 首先是其他人提到的填充问题。
  • 其次,即使事物被正确填充,取消引用具有偏移量的指针也是无效的,该偏移量将使其超出其指向的范围。编译器可以自由地假设这一点,并进行优化,如果您违反它,将导致未定义的行为。

但是,以下内容有效:

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是C ++ 0x的新手,基本上等同于boost::array。如果你不想要C ++ 0x或Boost,你可以使用std::vector(并将初始化器更改为data(3)),虽然这是一个更重要的解决方案,但它的大小可以从外面的世界,如果是,那么结果将是UB。

答案 1 :(得分:2)

是。此类是 布局兼容 标准布局,因为:

  • 您没有虚拟功能。
  • 所有数据成员都在一个访问说明符块(public:

正因为如此,它保证像C结构一样顺序排列。这使您可以读取和写入文件头作为结构。

答案 2 :(得分:1)

编译器在如何布局结构中的内存方面具有一定的灵活性。结构将永远不会与另一个数据结构重叠,但它可以在元素之间注入未使用的空间。在您给出的结构中,一些编译器可能会选择在z和数据之间添加4个字节的额外空间,以便可以对齐数据指针。大多数编译器都提供了packing一切紧密的方式。

编辑:无法保证编译器会选择紧密地打包x,y和z,但实际上它们将被打包好,因为它们是结构的第一个元素,因为它们是是一个两个大小的力量。

答案 3 :(得分:1)

或者你可以有一个operator []重载

float operator[](int idx)
{
 switch (idx)
{
case 0:
  return x;
case 1:
  return y;
case 2:
 return z;
}
assert (false);
}

答案 4 :(得分:1)

您的解决方案无效,但如果您可以确保(或知道)您的编译器将“做正确的事情”(特别是通过控制x,y和z元素之间的填充),您就可以了。在这种情况下,我会完全删除data成员并使用operator[]

我偶尔会看到这样的东西。它遇到了完全相同的问题,但确实可以保存您存储的数据指针,并允许更好的v[0]语法而不是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) {}
}
编辑:ildjam提示使用访问者而非成员的兼容版本,类似。

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];
};

答案 5 :(得分:-1)

做这样的事情:

float data[3];
float& x, y, z;

    Vector3D() : x(data[0]), y (data[1]), z(data[2]) { data [0] = data [1] = data [2] = 0;}