您可以将双精度数组重新解释为包含双精度数组的结构吗? [重复]

问题描述 投票:0回答:1

我正在使用一个库,它将 3D 笛卡尔向量数组表示为

double
的连续一维数组,其中三个后续条目对应于一个向量的笛卡尔分量。我还有一个自写的 3D 向量类
Vector3
,它实现了一些算术。我想将这个普通的
double
数组视为
Vector3
对象数组,如下所示:

class Vector3 {
  // Some functions and operators
  double m_pData[3]; // the components of the vector
};

double *pd = GetFromLibrary(); // The input raw data
Vector3 *pv = (Vector3*)pd; // Treat raw data as array of objects...

pv[3].m_pData[1] = 17.5; // Set the Y component of the fourth vector

我在几个不同的编译器和平台上尝试了这段代码,它工作得很好。从天真的角度来看,它当然应该总是有效,但我不确定是否会出现任何对齐问题。 C++ 标准是否规定这是允许的?如果没有,有什么方法可以修改代码以使其符合标准,而无需将数据复制到不同的内存位置?

或者以不同的方式提问:标准是否保证

Vector3
的普通数组拥有其所有
double
数据成员而没有间隙,我们是否会发生编译器插入一些填充以进行对齐(可能是32字节)?

c++ arrays class memory-alignment type-punning
1个回答
1
投票

即使对齐和尺寸/布局正确,从技术上讲仍然是符合标准的 UB。当从未显式或隐式创建该类型的对象时,您不能强制转换为某种类型(此处为

Vector3
)假装该类型的对象存在。结果将是仍然指向原始
double
对象的指针,但表达式类型不匹配,因此任何成员访问都将具有未定义的行为,就像
pv[3]
中的任何指针算术一样。实际上,编译器可能不会太在意(但我也不知道他们现在或将来是否承诺允许这种使用)。

对于对齐本身:

Vector3
的对齐要求在技术上可能比
double
更严格,因此
GetFromLibrary
返回的指针可能会错位。这可以在您所依赖的 ABI 规范中查找或通过添加
static_assert(alignof(Vector3) <= alignof(double));
来查找。然而,我不认为任何常用的 ABI 都能做到这一点。

对于其他布局问题:从技术上讲,

Vector3
的末尾可以有填充。不过,我再说一遍,我不知道有任何 ABI 具有这样的行为。您也可以使用
static_assert(sizeof(Vector3) == sizeof(double)*3);
来验证这一点。不允许在数组成员之前或数组元素之间进行填充。


请注意,我在上面假设您的类是 standard-layout 并且没有任何其他非静态数据成员或任何基类。这也意味着没有

virtual
成员函数等。

如果不是这种情况,那么数组成员之前也可以有填充,并且大小和对齐正确的可能性要小得多(特别是如果有

virtual
函数)。同样,具体布局将在适用的 ABI 规范中指定。


此外,如果不是在两个实例中使用相同的标量类型 (

double
),而是使用不匹配的标量类型(例如
double
中的
Vector3
,但指向
uint64_t
数组的指针),则编译器将不会宽容。这将是一个直接的别名违规,本身就是 UB 和编译器进行优化的行为,因此行为将默默地不符合预期。

© www.soinside.com 2019 - 2024. All rights reserved.