如何键入 - 将数量数组提升到基础类型?

时间:2015-09-25 12:51:36

标签: c++ visual-c++ boost undefined-behavior type-punning

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

  • OpenGL缓冲区填充命令。这些只需要const void *,并期望在解除引用时找到floatdouble值的数组。他们阅读了数据。

  • 来自BLAS和LAPACK的不同实现的线性代数函数(例如gemmgesv)。这些通常会将float *double *带到给定数组。他们都读取和写入数据。

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

所以,我们假设对于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()传递给期望在地址读取100个T类型对象数组的函数?

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

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

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

    (1)改编自Zen of Python

1 个答案:

答案 0 :(得分:2)

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

有一件事你没有提及,应该添加到要检查的条件列表中:包装金额类型的对齐应该与基础类型的对齐。 (见alignof)。

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

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

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

¹,也许调试断言&q.value() == &q