Eigen 的意外行为

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

我有一些 C++ 代码显示错误,但我无法理解为什么。 不过,我设法将代码简化为一个小示例。

我使用的是 MSVC 19.34.31944,以及线性代数库 Eigen 的最新版本 (3.4.0)。 编译选项是

/Oxt /std:c++20 /EHs
加上包含 Eigen 所在的位置。

第一个例子:

#include "Eigen/Dense"
#include <iostream>

std::pair<Eigen::Vector2d, double> func() {
    return { Eigen::Vector2d{11, 0}, 0 };
};

int main(int argc, char *argv[]) {

    const Eigen::Vector2d &result = func().first;

    std::cout << *result.data() << "  " << *(result.data() + 1) << std::endl;
    std::cout << result.transpose() << std::endl;
    std::cout << func().first.transpose() << std::endl;

    return 0;
}

这里我应该得到一个等于[11, 0]的向量,所以输出应该是:

11  0
11  0
11  0

但是,我有:

11  0
6.95158e-310 6.95145e-310
11  0

我无法在调试中或在 Linux 中使用 g++ 重现此行为(这意味着我得到了正确的行为)。此外,如果我在某个时候添加

std::cout << result << std::endl
(没有
.transpose()
),错误就会消失。所有这些让我认为这是一些内存错误。 起初我认为这是因为结果是保存为常量引用的右值的成员,但它似乎是有效的。请注意,不通过引用获取结果会给出预期的行为,但由于看似无用的打印也隐藏了错误,我无法断定此引用业务就是原因。

然后我认为这是由于

transpose
函数的错误使用造成的。然后我想到了第二个例子:

#include "Eigen/Dense"
#include <iostream>
#include <numbers>

// Computes the angle between two 2D vectors in [-pi, pi]
inline double computeAngle(const Eigen::Vector2d &vec1, const Eigen::Vector2d &vec2) {
    double angle = std::atan2(vec2(1), vec2(0)) - std::atan2(vec1(1), vec1(0));
    angle = angle > std::numbers::pi ? angle - 2.0 * std::numbers::pi : angle;
    angle = angle < -std::numbers::pi ? angle + 2.0 * std::numbers::pi : angle;
    return angle;
}

std::pair<Eigen::Vector2d, double> func() {
    double coeffMid = std::sin(2 * std::abs(computeAngle(Eigen::Vector2d{ 5, -5 }, Eigen::Vector2d{ -5, -5 })));
    std::cout << coeffMid << std::endl;

    Eigen::Vector2d center = (Eigen::Vector2d{ 10, 0 } + Eigen::Vector2d{ 0, 0 }) / 2;

    return { Eigen::Vector2d{5, 0}, 0 };
}


int main(int argc, char *argv[]) {
    
    const Eigen::Vector2d &result = func().first;

    for (size_t i = 0; i < 5; i++) {
        const Eigen::Vector2d foo = result + result;
        std::cout << foo[0] << " " << foo[1] << std::endl;
    }
    return 0;
}

我希望到达的地方

1.22465e-16
10 0
10 0
10 0
10 0
10 0

但是我有

1.22465e-16
10 0
20 0
40 0
80 0
160 0

这个例子没有多大意义,因为它最初是一个较大的例子,后来被简化了。有些行看起来没用(在 func 中,

computeAngle
中的三元组),但它们确实改变了行为。

在我看来,我错过了一些明显的东西,因为这两个例子都很小,但我不知道是什么。我知道用 const 引用捕获函数输出并不流行,我已阅读并理解原因,但标准仍然允许它,因此它不是此错误的原因。不然我没看懂标准!

有人对此有一些见解吗?

提前致谢

c++ eigen
1个回答
0
投票

我写了一个关于表达式模板的较长答案,但删除了它,因为我意识到我错了。

这只是依赖于未定义行为的代码。在计算表达式

func
时,临时寿命延长会延长
func().first
结果的寿命。之后,
result
是一个悬空引用,取消引用它可以做任何事情。

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