Eigen中Lambda返回表达式时结果异常的原因咨询
Eigen Lambda表达式与普通函数返回值差异问题
问题描述
我尝试将以下普通函数的逻辑迁移至Lambda表达式:
Vector3d fun(Vector3d const& point) { Vector3d const b{ 0., 0., 30. }; return b + point.normalized(); }
但发现Lambda中若不在返回前通过eval()显式求值,或先将结果赋值给变量再返回,返回结果会异常;而普通函数直接返回该表达式却能正常运行。我查阅了Eigen文档中按值返回的说明,也不确定如何应用陷阱提示,希望理解二者差异的原因。
测试Demo代码
#include <Eigen/Dense> #include <iostream> using Vector3d = Eigen::Vector3d; Vector3d fun(Vector3d const& point) { Vector3d const b{ 0., 0., 30. }; return b + point.normalized(); } int main() { auto lamb = [](Vector3d const& point) { Vector3d const b{ 0., 0., 30. }; return b + point.normalized(); //Vector3d ret = b + point.normalized(); return ret; }; Vector3d const point{ 1., 2., 3. }; Vector3d const resultl = lamb(point); std::cout << resultl.x() << " / " << resultl.y() << " / " << resultl.z() << "\n"; Vector3d const resultf = fun(point); std::cout << resultf.x() << " / " << resultf.y() << " / " << resultf.z() << "\n"; }
问题原因与解决方案
核心差异:返回类型推导的不同
- 普通函数明确指定了返回类型为
Vector3d,编译器会自动将b + point.normalized()生成的Eigen表达式模板对象隐式转换为Vector3d,在返回时完成实际计算,避免了悬垂引用问题。 - 未指定返回类型的Lambda会通过
auto推导返回类型,这里b + point.normalized()返回的是一个临时的表达式模板对象(例如Eigen::CwiseBinaryOp),该对象内部持有对point.normalized()返回的临时归一化向量的引用。当Lambda返回这个表达式对象时,内部引用的临时向量已经被销毁,后续赋值给Vector3d时访问的是已释放的内存,导致结果异常。
可行解决办法
- 显式指定Lambda返回类型:将Lambda定义为
[](Vector3d const& point) -> Vector3d,让编译器像处理普通函数一样,自动将表达式转换为Vector3d后返回,完成求值。 - 显式求值后返回:使用
eval()强制表达式求值为Vector3d,或者先将结果赋值给局部变量再返回(如Demo中注释的代码),两种方式都会将计算结果存储到持久的Vector3d对象中,避免悬垂引用。
对应Eigen文档陷阱
这个问题对应Eigen陷阱提示中避免返回表达式模板对象的内容:表达式模板对象只是计算的“蓝图”,而非实际数值存储,内部可能持有临时对象的引用。若返回这类对象,引用的临时对象会在函数(Lambda)结束时销毁,导致后续访问失效。普通函数因指定了具体返回类型,编译器自动触发转换求值;而Lambda的自动推导保留了表达式模板类型,从而引发问题。
内容的提问来源于stack exchange,提问作者ridilculous
相关产品推荐
相关产品推荐

