如何键入 - 将数量数组增加到基础类型?

Rei*_*ica 5 c++ boost undefined-behavior visual-c++ type-punning

我正在构建一个动态动画和渲染系统,我想使用Boost.Units来表示物理量,以获得良好的尺寸安全性.但是,我必须将数量数组传递给对Boost一无所知的函数,例如:

  • OpenGL缓冲区填充命令.这些只需要a const void *并期望在解除引用时找到一个float或一个数组double.他们读了数据.

  • 线性代数函数(例如gemmgesv)来自BLAS和LAPACK的不同实现.这些通常采用a float *double *给定的数组.它们都可以读取和写入数据.

我知道boost::units::quantity<U, T>有一个const T& value()成员可以直接引用所包含的T值.我还验证了a boost::units::quantity<U, T>是一个标准布局结构,只有一个类型的非静态数据成员T.

所以,让我们假设a boost::units::quantity<U, T> q,以下成立:

  • static_cast<const void*>(&q) == static_cast<const void*>(&q.value())
  • sizeof(q) == sizeof(T)

我的问题是:给定一个数组boost::units::quantity<U, T> a[100];,是否安全:

  1. 传递&a[0].value()给一个期望T在地址读取100个类型对象的数组的函数?

  2. 传递reinterpret_cast<T*>(&a[0])给一个函数,该函数将T在地址处写入100个连续的类型值?

我很清楚这可能是未定义的行为,但是现在我必须遵循"实用性节拍纯度" (1)原则.即使这是UB,它是否会做出预期的事情,还是会以不可预见的方式咬人?因为这可能是编译器特定的:我需要这个用于现代MSVC(来自VS 2015).

如果这不安全,有没有办法真正安全地做到这一点?"this"指的是"使用带有OpenGL的Boost.Units和只有C接口的数字处理程序",而不会不必要地复制数据.


(1)改编自Python禅宗.

seh*_*ehe 3

是的,这看起来像是你可以做的事情。

\n\n

不过,有一件事您没有提到,应该添加到要检查的条件列表中:包装金额类型的对齐方式应与基础类型的对齐方式相匹配。(看alignof)。

\n\n

因此,在实践中,我只会使用一些 static_asserts\xc2\xb9 来编写这样的代码,以保护使重新解释有效的假设。

\n\n

如果添加 T 与此相同的断言remove_cv_t<decltype(q.value())>应该是可靠的。

\n\n

有了这些预防措施,就不应该有 UB,而应该只有 IB(实现定义的行为),因为您的特定平台上的reinterpret_cast 的语义。

\n\n

\xc2\xb9 或许调试断言&q.value() == &q

\n