【发布时间】:2015-12-23 07:32:23
【问题描述】:
我正在构建一个动态动画和渲染系统,我想使用Boost.Units 来表示物理量以获得良好的尺寸安全性。但是,我将不得不将数量数组传递给对 Boost 一无所知的函数,例如:
OpenGL 缓冲区填充命令。这些只是采用
const void *并期望在取消引用时找到float或double值的数组。他们读取数据。来自 BLAS 和 LAPACK 不同实现的线性代数函数(例如
gemm或gesv)。这些通常将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];,是否安全:
将
&a[0].value()传递给一个函数,该函数希望在该地址读取一个包含100 个T类型对象的数组?将
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