捕获Eigen::Vector到std::function时出现异常行为
Eigen::Vector2d Lambda表达式返回结果不一致问题
用户代码如下:
Eigen::Vector2d xT = Eigen::Vector2d(1.7, 3.4); // chosen at random std::function<Eigen::Vector2d(Eigen::Vector2d)> test1 = [xT](Eigen::Vector2d x) { Eigen::Vector2d y = x - xT; return y; }; std::function<Eigen::Vector2d(Eigen::Vector2d)> test2 = [xT](Eigen::Vector2d x) { return x - xT; }; std::cout << "\n" << test1(xT) << "\n"; // outputs (0, 0) i.e. x - xT std::cout << "\n" << test2(xT) << "\n"; // outputs (-1.7, -3.4) i.e. -xT
用户疑问:我认为test1和test2应输出相同结果,但test2输出错误(实际为-xT而非x-xT)。用double类型做类似测试时一切正常,请问这是什么原因?
问题解答
这是Eigen**表达式模板(Expression Templates)**机制引发的未定义行为,具体原因如下:
- Eigen为优化性能,二元运算(如
x - xT)不会立即计算结果,而是返回一个轻量的表达式对象(例如Eigen::DifferenceExpr)。该对象仅存储对运算数的引用和运算逻辑,直到实际需要取值时才执行计算。 - 在test2的lambda中,
return x - xT;直接返回了这个表达式对象,lambda的返回类型被推导为该表达式类型(而非Eigen::Vector2d)。 - 由于lambda的参数
x是值传递的临时对象,lambda执行完毕后x会被销毁。当std::function尝试将表达式对象转换为Eigen::Vector2d时,表达式需要访问已失效的x的引用,触发未定义行为,最终得到错误结果。 - test1中先将
x - xT赋值给Eigen::Vector2d y,这一步会立即触发表达式计算,将结果存储到实际的Vector对象中,返回的y是有效的独立对象,因此结果正确。
用double测试正常是因为double是基础类型,x - xT会直接计算出具体值,返回的是实际的double值,不存在延迟计算和引用失效的问题。
解决方法
有两种可行的修复方式:
- 沿用test1的写法,先将表达式结果赋值给Vector对象再返回;
- 显式指定lambda的返回类型为
Eigen::Vector2d,强制在return时立即计算表达式:std::function<Eigen::Vector2d(Eigen::Vector2d)> test2 = [xT](Eigen::Vector2d x) -> Eigen::Vector2d { return x - xT; };
内容的提问来源于stack exchange,提问作者user13438125
相关产品推荐
相关产品推荐

