Rei*_*ica 5 c++ boost undefined-behavior visual-c++ type-punning
我正在构建一个动态动画和渲染系统,我想使用Boost.Units来表示物理量,以获得良好的尺寸安全性.但是,我必须将数量数组传递给对Boost一无所知的函数,例如:
OpenGL缓冲区填充命令.这些只需要a const void *并期望在解除引用时找到一个float或一个数组double.他们读了数据.
线性代数函数(例如gemm或gesv)来自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];,是否安全:
传递&a[0].value()给一个期望T在地址读取100个类型对象的数组的函数?
传递reinterpret_cast<T*>(&a[0])给一个函数,该函数将T在地址处写入100个连续的类型值?
我很清楚这可能是未定义的行为,但是现在我必须遵循"实用性节拍纯度" (1)原则.即使这是UB,它是否会做出预期的事情,还是会以不可预见的方式咬人?因为这可能是编译器特定的:我需要这个用于现代MSVC(来自VS 2015).
如果这不安全,有没有办法真正安全地做到这一点?"this"指的是"使用带有OpenGL的Boost.Units和只有C接口的数字处理程序",而不会不必要地复制数据.
是的,这看起来像是你可以做的事情。
\n\n不过,有一件事您没有提到,应该添加到要检查的条件列表中:包装金额类型的对齐方式应与基础类型的对齐方式相匹配。(看alignof)。
因此,在实践中,我只会使用一些 static_asserts\xc2\xb9 来编写这样的代码,以保护使重新解释有效的假设。
\n\n如果添加 T 与此相同的断言remove_cv_t<decltype(q.value())>应该是可靠的。
有了这些预防措施,就不应该有 UB,而应该只有 IB(实现定义的行为),因为您的特定平台上的reinterpret_cast 的语义。
\n\n\xc2\xb9 或许调试断言&q.value() == &q