【问题标题】:How to type-pun Boost quantity arrays to the underlying type?如何将 Boost 数量数组键入到基础类型?
【发布时间】:2015-12-23 07:32:23
【问题描述】:

我正在构建一个动态动画和渲染系统,我想使用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 类型的连续值的函数?

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

如果这不安全,有没有办法真正安全地做到这一点? “this”指的是“将 Boost.Units 与 OpenGL 和仅具有 C 接口的数字运算器一起使用”, 不会不必要地复制数据。


(1)改编自Zen of Python

【问题讨论】:

  • 我想你说的UB是指IB?因为没有人应该对 UB 不屑一顾。
  • 具有讽刺意味的是,这些函数最终出现在一个基本上是 void* 的接口中。因此,在编译这些外部库时,就已经做出了关于别名的决定。所以你真的可以选择在哪里建立你的别名规则,如果有的话最终被二进制可执行文件忽略。 c++ 缺少的是表达这一点的好方法。

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


【解决方案1】:

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

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

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

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

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

¹也许还有&q.value() == &q的调试断言

【讨论】:

  • 但是违反严格别名规则的是UB,而不是IB。 (在调用的函数中违反了,即BLAS/LAPACK/OpenGL C代码违反了。)
  • 嗯。有这个方面。我不知道这是否一定是一个问题,但这肯定是一个需要研究的领域。
  • @dyp 严格的别名也是我关心的问题。同时,在该地址实际上有一个float 类型的对象(作为quantity 类型的完整对象的子对象)。所以也许这并没有违反严格的别名?
  • 关于别名规则的要点是编译器是否必须意识到它以防止不安全的优化,AFAICT。因此,即使类型双关语是有效的(当解释回确切的原始类型时不是 UB),它也可能“掩盖”编译器的视图并使其进行不安全的优化。我真的必须更多地了解所涉及的 API。也许其他人会参与进来
  • @Angew 嗯,这是真的。对于这种情况,C++11[class.mem]p20 有一个明确的例外;在 C++14 中,它的表述方式有所不同,但并不是为了禁止这个用例。不过,我并不完全确定指针算法。
猜你喜欢
  • 2012-07-06
  • 2014-06-25
  • 1970-01-01
  • 2018-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-14
  • 1970-01-01
相关资源
最近更新 更多