Eigen库:那些年我们一起经历的bug_C/C++_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > C/C++ > Eigen库:那些年我们一起经历的bug

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

 2014/9/24 20:55:39  cherishLC  程序员俱乐部  我要评论(0)
  • 摘要:1、使用auto声明新变量时不要局部eval()这句话神马意思呢?我们知道,在C++函数中最好不要返回局部变量,否则可能产生因为局部变量被回首而引发的错误。而这个问题正是源于此。在以下这个bug中:http://eigen.tuxfamily.org/bz/show_bug.cgi?id=505“a*b”就会引发自动的eval(),从而产生局部变量,该局部变量被一个表达式所引用,导致结果不可预知。最新版本的Eigen已经解决了这个问题~~~那么,这个bug是不是完全不存在了呢?答案是NO。。。
  • 标签:经历 一起 我们
1、使用auto声明新变量时不要局部eval()
这句话神马意思呢? 我们知道,在C++函数中最好不要返回局部变量,否则可能产生因为局部变量被回首而引发的错误
而这个问题正是源于此。
在以下这个bug中:
http://eigen.tuxfamily.org/bz/show_bug.cgi?id=505 
“a*b”就会引发自动的eval(),从而产生局部变量,该局部变量被一个表达式所引用,导致结果不可预知。
最新版本的Eigen已经解决了这个问题~~~那么,这个bug是不是完全不存在了呢?
答案是NO。。。。
看以下的代码:

class="C++">    auto A_mul_B_plus_C = C + (A * B).colwise().sum();
    auto A_mul_B_Eval_plus_C = C + (A * B).colwise().sum().eval();

二者的结果都是表达式,但是第二个表达式中局部变量被eval()了,产生了一个临时的Matrix,该临时变量会被回收,导致结果的不正确。
解决方案:
  • 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();

完整的代码参见:http://eigen.tuxfamily.org/bz/show_bug.cgi?id=883


2、不用eval()也是不行的!(最新版本(3.2.2)不存在这个问题了)
也许你会有所疑问,我干嘛要手动eval()呢?
这源于另一个bug:
一年前接触Eigen库的时候,写过这么一段代码

      Eigen::MatrixXd m=Eigen::MatrixXd::Ones(3,4);
      m.array().rowwise()/=m.array().colwise().sum();
      std::cout<<m<<std::endl;

结果大跌眼镜(最新版本的输出没问题了):
  • 0.333333 0.333333 0.333333 0.333333
  • 0.428571 0.428571 0.428571 0.428571
  • 0.567568 0.567568 0.567568 0.567568

原因可能是等号右边时表达式,左边每行除以右边时,右边的表达式都会被重新计算。。。
所以当时的版本必须eval()一下!好在现在这个bug消除了!
另外多说一句,基于效率考虑,可能也要eval()一下,但是我调了下代码,当前版本的Eigen右侧的表达式是只计算一遍的,放心的不eval()吧!

发表评论
用户名: 匿名