正确使用Eigen :: Transpose ?

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

我有一个旋转类,可以使用四元数或旋转矩阵来表示旋转。如下定义转置函数时,我没有问题:

Matrix3 Rot3::transpose() const {
  // quaternion_ is a class variable of type `Quaternion`.
  return quaternion_.toRotationMatrix().transpose();
}

当我使用Eigen::Transpose切换到推荐版本时,我的单元测试失败(并且我得到了NaN)

Eigen::Transpose<const Matrix3> Rot3::transpose() const {
  // quaternion_ is a class variable of type `Quaternion`.
  return quaternion_.toRotationMatrix().eval().transpose();
}

我需要以这种怪异的方式使用.eval(),否则编译器会发出模糊的错误消息。我的猜测是我对Eigen::Transpose声明的使用与我返回的内容不一致。关于此方法为何表现如此奇怪的任何帮助或建议,以及有关此方法正确方法的任何建议?

c++ eigen quaternions
1个回答
0
投票

Eigen::Transpose只是围绕现有矩阵的wrapper类。它保留对矩阵的引用,并在反转索引的同时中继调用以访问元素。此类的目标是能够使用转置矩阵,而不必实际复制矩阵本身。

换句话说,这是Eigen::Transpose类的定义的非常简化的版本:

Transpose

您可以看到实际的来源struct Transpose<const Matrix3> { const Matrix3& m_matrix; const float& coeffRef(int row, int col) const { return m_matrix.coeffRef(col,row); } }

关键部分是here类存储给定矩阵的reference

现在第二版Transpose函数会发生什么?

  • 您使用transpose创建一个临时的Matrix3
  • 然后您在此临时矩阵周围创建quaternion.toRotationMatrix().eval()包装器,存储对此矩阵的引用。

从函数返回时,返回的Transpose具有对超出范围的对象的引用。这称为Transpose,它导致未定义的行为(您看到dangling reference的原因很可能是临时矩阵所在的内存已被其他数据覆盖)。该代码等效于此:

NaN

请注意,在第一个版本中不会发生这种情况,因为您的返回类型为Eigen::Transpose<const Matrix3> Rot3::transpose() const { // Equivalent to your second version Matrix3 temp = quaternion_.toRotationMatrix().eval(); Transpose<const Matrix3> result = temp.transpose(); // Holds ref to temp -> Leads to UB return result; } 。在这种情况下,您创建的Matrix3对象将转换为要返回的新Transpose对象,该对象将复制系数。这是您的第一个功能的等效版本。

Matrix3

如果您仍然想继续使用Matrix3 Rot3::transpose() const { // Equivalent to your first version Matrix3 temp = quaternion_.toRotationMatrix().eval(); Matrix3 result = temp.transpose(); // Does a full copy of the transpose of `temp` return result; } 作为返回类型(也许您[[really避免复制操作),则需要将旋转矩阵存储在一个永久位置(例如,作为缓存的Eigen::Transpose ]类中的成员变量),以避免出现悬而未决的引用问题。

另一个选择是传递要填充的预先存在的矩阵,例如

Matrix3

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