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()吧!