我们能否将 `Eigen::Vector<T, D + 1>& x` `reinterpret_cast` 为 `Eigen::Vector<T, D>&` 以从 `x` 中提取第一个 `D` 分量?

问题描述 投票:0回答:2

我需要计算

D
维函数的函数值和梯度,并将这些值加在一起。我认为将梯度部分简单地存储在第一个
D
分量中,并将函数的值存储在
D+1
维向量的最后一个分量中,这在计算上是有益的。

但是,如何从

D
维向量中提取第一个
D+1
分量(即梯度部分)?我知道有切片选项,但我不想在这里添加任何无意义的开销。所以,我试着简单地在我的
reinterpret_cast<Eigen::Vector<T, D>&>
上做一个
Eigen::Vector<T, D + 1>
并且它起作用了;但这真的能保证工作(并且安全)吗?

c++ c++20 eigen reinterpret-cast
2个回答
5
投票

它会导致未定义的行为。

只有当泛左值的类型与对象的类型similar 时,您才可以通过泛左值使用类的成员。 相似表示类型相同到

const
资格。

当你像这样使用

reinterpret_cast
时,你改变了左值的类型,但你仍然让它引用与原始类型相同的对象。 (如果在同一地址有一个目标类型的对象与原始对象是pointer-interconvertible
,则有一些例外,但我怀疑是否可以保证
Eigen::Vector
以这样的方式实现
Eigen::Vector<T, D+1>
 是标准布局,其开头包含一个 
Eigen::Vector<T, D>

子对象,这是应用例外的先决条件。)

即使您不那么关心 UB,至少您也在对这两个类的内存布局做出假设。但是没有人保证你的布局。 (不过,就算保底了,还是有UB的。)

0
投票

你不需要切片操作,你想要块操作

。大多数(全部?)它们都带有模板版本。如果 
D
 是运行时变量,要获取向量的前 
D
 元素,请调用 
vector.head(D)
。如果它是一个编译时常量,使用
vector.head<D>()

.

返回的 block 表达式对象类似于 Eigen Map

,因为它实际上是一个零开销引用,并且完全按照您的意愿行事。
// act like reference
auto first_d = vector.head<D>();
// copy into new vector
auto copy = first_d.eval();
// or
Eigen::Vector<double, D> copy2 = first_d;

在 Eigen

 中使用 
auto 的常见警告适用,但这种用法是可以的。如果您想安全起见,请拼出类型或不要将其作为变量保留,仅将其用作表达式的一部分。

如果您在没有

-DNDEBUG
的情况下进行编译,将会进行范围检查,除非编译器可以将其优化掉(模板参数可能就是这种情况)。

回到最初的问题:不,这不安全。即使您相信 Eigen 永远不会改变固定大小类型的内部布局(合理的假设),较小的向量可能会有更大的对齐。

alignof(Vector3d) < alignof(Vector2d)
。这将导致 Eigen 创建假定更高对齐的机器指令(例如 x86 上的
movapd
movupd
),这将在运行时失败。

© www.soinside.com 2019 - 2024. All rights reserved.