POD结构(相同类型的成员):成员是否位于连续的内存位置?

时间:2019-09-05 15:27:00

标签: c++ struct memory-alignment

给予

template <typename T>
struct Vector3d { T x, y, z; };
  • 可以安全地假设x,y和z位于连续的内存位置吗?

  • 假设T = floatT = double至少是安全的吗?

  • 是否可以跨平台执行?

注意:只要x,y,z是连续的,我不介意在z之后填充

4 个答案:

答案 0 :(得分:4)

  

可以安全地假设x,y和z位于连续的内存位置吗?

从技术上讲,这种语言没有这种保证。

另一方面,它们也不必是连续的,并且在实践中它们很可能是连续的。

  

是否可以跨平台实施?

确保对象位于连续内存位置的跨平台方式是数组:

template <typename T>
struct Vector3d { T components[3]; };

数组还使使用指针算法遍历对象合法。

答案 1 :(得分:4)

  

可以安全地假设xyz位于连续的内存位置吗?

标准并不能保证如此。

但是在实践中,理智的实现方式不会在相同类型的相邻字段之间插入任何填充(因为这样的填充从没有必要 1 )。

如果您想提高安全性,请添加static_assert

static_assert(sizeof(Vector3d<float>) == 3 * sizeof(float));
  

假设T = floatT = double至少是安全的吗?

据我所知,字段类型在这里没有任何区别。


1-保证数组不包含填充。由于您可以创建任何类型的数组,因此实现必须能够将任何单个类型的对象彼此相邻且无填充。

答案 2 :(得分:3)

不,绝对不能保证相同类型的结构元素之间不会存在填充,即使对于double之类的“大型”普通旧数据类型也是如此。此外,尝试通过指向另一个元素的指针的指针算术到达一个元素的行为是不确定的。

最好写

template <typename T>
struct Vector3d { T t[3]; };

保证连续性和指针算术,并为xyz提供访问功能。

如果您不喜欢调用函数的语法,并且愿意忍受struct本身最有可能出现的某些开销,那么您始终可以绑定引用:

template <typename T>
struct Vector3d
{
    T t[3];
    T& x = t[0];
    T& y = t[1];
    T& z = t[2];
};

答案 3 :(得分:-2)

向结构和类中添加填充的唯一原因是为了满足其成员的对齐要求。请注意,结构的对齐方式是其成员具有最大对齐要求的对齐方式。结构的大小是其对齐方式的倍数,为此添加了尾随填充。

由于Vector3d的成员属于同一类型,因此对齐要求已经得到满足,因此,在成员之间或结构的末尾没有任何填充。

C ++标准中没有要求无缘无故地插入任意填充。

要确保100%正确,请投入static_assert

static_assert(sizeof(Vector3d<float>) == 3 * sizeof(float), "Unexpected layout.");
static_assert(sizeof(Vector3d<double>) == 3 * sizeof(double), "Unexpected layout.");

有人说,保证没有在C ++标准中明确阐明,因此,人们不能依赖它。但是,C ++标准通常没有得到充分说明,因此需要了解其背后的原理。我个人认为,这些人没有充分的理由散布恐惧,不确定和怀疑。