带指针的班级访问成员

Access members of class with pointer

本文关键字:访问 成员 指针      更新时间:2023-10-16

我正在寻找C 中现代opengl的示例,其中结构用于保存有关顶点坐标的数据和3个坐标颜色向量

struct VertexData{
    float x, y;
    float r, g, b;
}
std::vector<VertexData> myData = {
    {.x = 0, .y = 0, .r = 0, .g = 0, .b = 0},
    {.x = 0, .y = 0, .r = 0, .g = 0, .b = 0}
}
float *ptr = (float*) &myData[0];

要访问向量的第二个元素的x值,我可以加速ptr[5],用于将顶点缓冲区传递给OpenGL的技术。我的问题是:我可以在更复杂的班级中使用相同的技术吗?作为具体示例,如果我有Vertex类:

class Vertex {
public:
    float x, y, z;
    Vertex();
    // Other constructors here...
    Vertex operator+(const Vertex &other);
    // Overload of other operators like -,*,=, etc...
}
std::vector<Vertex> myData(100);
float *ptr = (float*) &myData[0];

使用ptr变量访问该向量中的所有元素仍然是安全的(也是一个好主意...)吗?我知道这在存在静态变量,不同类型,继承等的情况下可能很棘手,但是在这种情况下,只有普通的变量和功能作为成员,将使用指针为可靠>方法?

正如其他人已经提到的那样,您的这种方法是不可靠的,因为编译器可以选择添加您的struct。例如,如果您位于64位平台上,则编译器可以选择将struct至8字节对齐。

但是,使用指针访问班级成员的想法仍然可以正常工作。您可以使用sizeof获取struct的实际大小(以字节)。

在您的第一个示例中,看起来像这样:

float *ptr = (float*) &myData[0].x;

并访问这样的下一个x值:

ptr = (float*)(((char*)ptr) + sizeof(VertexData));

或,或者,如果您确定sizeof(VertextData)sizeof(float)的倍数,则可能是:

ptr += sizeof(VertexData) / sizeof(float);

这有点复杂,但可靠。另外,如果您愿意,您可以将物品包裹在宏中。

这种方法是否实用取决于您的特定情况。我会说在某些情况下它可能有用。


编辑:

尽管如此,使用这种方法存在一些危险。

要记住的最重要的事情是,如果您将某些元素插入向量,则可以重新分配整个存储,因此您以前的指针将不再有效。


编辑:

还有另一种方法,避免使用sizeof。要访问下一个x值,您可以使用:

ptr = (float*) (((VertexData*) ptr) + 1);

这应该编译为相同的结果。

根据C 标准,此技术具有未定义的行为。编译器可以自由添加成员之间的填充。因此,根据标准的原理,这是一个坏主意。

但是。

我认识的所有编译器(在过去的15年中,我已经与8个不同的C 编译器合作),在这种情况下不要添加填充。他们为什么会?因此,如果您敢于进入不确定的行为土地,则可以使用此技术。即使在复杂的情况下。继承,虚拟函数等。我知道的所有编译器,做逻辑上的事情,并在您的情况下将Float成员彼此相邻,并且他们的优化器在这种情况下不会失败。注意:该标准允许编译器在访问说明符之间重新排序成员,因此,如果您想站在安全方面(您已经离开了),请将所有成员放在同一访问说明符下(仍然,我还没有看到编译器,实际上是在访问说明符之间重新定位成员。)。

所以。根据标准: no ,它是可靠的吗?。根据当前的做法:以我的经验,是的。我还没有看到这样的编译器,因为这样的代码失败了。我鼓励任何知道这种编译器的人,不要保持沉默,并将其添加为答案。

注意:这是当前状态。它可能随时破裂。我只建议在知道自己在做什么时使用此技术,并且您知道可能的后果。而且不要忘记在您的代码中评论这个事实。