Eigen库:那些年我们一起经历的bug

本文深入探讨了Eigen库中eval()函数的使用场景与潜在风险,详细解析了避免局部变量错误的方法,并通过实例展示了如何正确地在不同情况下应用eval()函数,以确保代码的稳定性和效率。
[size=x-large][color=blue]1、使用auto声明新变量时不要局部eval()[/color][/size]
[size=large]这句话神马意思呢? 我们知道,在C++函数中最好不要返回局部变量,否则可能产生因为局部变量被回收而引发的错误。
而这个问题正是源于此。
在以下这个bug中:[/size][url]http://eigen.tuxfamily.org/bz/show_bug.cgi?id=505[/url]
[size=large]“a*b”就会引发自动的eval(),从而产生局部变量,该局部变量被一个表达式所引用,导致结果不可预知。
最新版本的Eigen已经解决了这个问题~~~那么,这个bug是不是完全不存在了呢?
答案是NO。。。。
看以下的代码:[/size]
    auto A_mul_B_plus_C = C + (A * B).colwise().sum();
auto A_mul_B_Eval_plus_C = C + (A * B).colwise().sum().eval();

[size=large]二者的结果都是表达式,但是第二个表达式中局部变量被eval()了,产生了一个临时的Matrix,该临时变量会被回收,导致结果的不正确。[/size]
[color=blue][size=large]解决方案:[/size][/color]
[size=large][list]
[*]1、不使用auto A_mul_B_Eval_plus_C,而是使用MatrixXd A_mul_B_Eval_plus_C这类的显式声明。(但这样不够灵活有没有!)
[*]2、使用eval(),对,你没看错,但是是在整条语句上使用eval();比如:auto A_mul_B_plus_C_EvalAll = (C + (A * B).colwise().sum().eval() ).eval(); //如果该变量要多次使用,推荐这种做法,这种做法也是最安全的(不会因为Eigen库还有之前a*b产生局部变量引发的错误)
[*]3、完全不使用eval(); 比如:auto A_mul_B_plus_C = C + (A * B).colwise().sum();
[/list][/size]
[size=large]完整的代码参见:[/size][url]http://eigen.tuxfamily.org/bz/show_bug.cgi?id=883[/url]
[size=large]更深入了解这个bug看下面这个链接:[/size][url]http://eigen.tuxfamily.org/bz/show_bug.cgi?id=99[/url]

[color=blue][size=x-large]2、不用eval()也是不行的!(最新版本(3.2.2)不存在这个问题了)[/size][/color]
[size=large]也许你会有所疑问,我干嘛要手动eval()呢?
这源于另一个bug:
一年前接触Eigen库的时候,写过这么一段代码[/size]
      Eigen::MatrixXd m=Eigen::MatrixXd::Ones(3,4);
m.array().rowwise()/=m.array().colwise().sum();
std::cout<<m<<std::endl;

[size=large]结果大跌眼镜(最新版本的输出没问题了):[/size]
[list]
[*]0.333333 0.333333 0.333333 0.333333
[*]0.428571 0.428571 0.428571 0.428571
[*]0.567568 0.567568 0.567568 0.567568
[/list]
[size=large]原因可能是等号右边时表达式,左边每行除以右边时,右边的表达式都会被重新计算。。。
所以当时的版本必须eval()一下!好在现在这个bug消除了!
另外多说一句,基于效率考虑,可能也要eval()一下,但是我调了下代码,当前版本的Eigen右侧的表达式是只计算一遍的,放心的不eval()吧![/size]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值