我有一个类来表示浮动的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浮点数以外的内存的风险?
答案 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;}