默认情况下,结构体内存的结构体在 C++ 中是如何排列的?

How is a struct of struct's memory arranged by default in C++?

提问人:Thibault de Villèle 提问时间:11/29/2019 最后编辑:Thibault de Villèle 更新时间:11/29/2019 访问量:140

问:

如果我想在 C++ 中定义一个类,例如用于 OpenGL 渲染,我喜欢这样做的方式,而且似乎也是最方便的,是首先定义一个类:MatrixVector

class vec3 {
    double x;
    double y;
    double z;
    [ ... ]
}

class vec4 {
    double x;
    double y;
    double z;
    double w;
    [ ... ]
}

现在,据我了解,当我创建一个 vec{3|4}(右???)时,的值应该在内存中是连续的。x, y, z{, w}

如果我这样创建我的矩阵:

class mat3 {
    vec3 _m[3];
    [ ... ]
}

class mat4 {
    vec4 _m[4];
    [ ... ]
}

矩阵类中每个向量的值在内存中总是彼此相邻吗?如果我将第一个元素的地址交给 OpenGL,它读取内存中接下来的 16 个值(对于 4x4 矩阵),它会按顺序读取矩阵的 16 个值,还是来自程序中其他地方的其他信息会妨碍?x, y, z{, w}

编辑(2019 年 11 月 29 日):更正了错别字

C++ OpenGL 优化 内存 向量

评论

0赞 Victor Gubin 11/29/2019
请参阅数据结构对齐。同样,最好使用事实上的标准库,而不是发明自己的线性代数库。GLM 使用 MMX/SSE/AVX SIMD 指令进行了优化,矩阵操作速度确实很出色。另请查看 learnopengl 资源,您可以找到此库使用示例。OpenGL Mathematics (GLM)
0赞 Thibault de Villèle 11/29/2019
我会使用它,只是因为它是我课程的作业。我们必须创建自己的基本线性代数,并能够在我们课程的所有其他作业中使用它@VictorGubin
0赞 Victor Gubin 11/29/2019
好的,在这种情况下,最好选择定义向量,因为您可以像 GLM 一样使用模板。struct vec3 { float xyz[3]; constexpr vec(float x, float y, float x) : xyz( {x,y,z} ) noexcept {} float x() const noexcept { return xyz[0];} ... }
0赞 Victor Gubin 11/29/2019
还要检查 C++ 11 对齐说明符
0赞 Max Langhof 11/29/2019
该标准允许任意填充,因此从技术上讲,这是实现定义的。不过,我不知道有任何实现会为您的情况做一些意想不到的事情,所以您只需添加一个 .static_assert(sizeof(vec3) == 3 * sizeof(double));

答:

1赞 eerorika 11/29/2019 #1

矩阵类中每个向量的 x、y、z{、w} 的值在内存中是否总是彼此相邻?

语言可能无法保证如此,但在实践中可能是连续的。

它会读取矩阵的 16 个值吗?

在 C++ 中未定义对成员进行索引的行为。API 可能是用 C 语言编写的,它可能有不同的规则。

有一个数据结构可以迭代,并保证有 16 个相邻元素:16 个双精度数组。

评论

0赞 MSalters 11/29/2019
C 的规则几乎相同。
0赞 MSalters 11/29/2019 #2

稳健的解决方案是从 .对于编译器来说,它只是表示 的偏移量的一种方式,而您希望它为 1。你可以通过写作来实现同样的目标double[16]&vec3::yy

struct vec3 {
   double* base;
   double& x() { return *base; }
   double& y() { return *(base+1); }
   double& z() { return *(base+2); }
};
struct mat3 {
   double values[9];
   vec3 operator[](size_t s) { return vec3{values+3*s}; }
};

它都是内联的,因此编译器仍然可以静态计算偏移量。使用 时,不会在运行时调用函数。y()

评论

0赞 gman 12/1/2019
除了在调试版本和调试时,这可能真的很烦人。
0赞 Max Langhof 11/29/2019 #3

该标准允许任意填充,因此从技术上讲,成员在内存中是否连续是实现定义的。不过,我不知道有任何实现会为您的情况做一些意想不到的事情,所以您只需添加一个 .static_assert(sizeof(vec3) == 3 * sizeof(double));

同样,在代码中访问一堆成员,就好像它们是一个数组一样(即通过指针算术)是标准未定义的行为,因为那里没有实际的数组对象。现在,如果你给 OpenGL 这个在正确位置有值的东西,应该没有问题(因为你的编译器大概不会接触 OpenGL 代码,而 OpenGL 只关心字节是否是它们应该的样子)。struct

但请注意,对于我要说的课程范围来说,这只是“好的”。对于实际的生产代码,这些假设太脆弱,应该首选更健壮(但可能不太方便)的方法。