Registered Member
|
Consider the following:
This particular piece of code works fine, but in a more complex context matrix N appears to be non-initialized. If instead of
I put
or
then it works. What is the problem here? Is Eigen unable to handle constant references to temporaries? Is it guaranteed to work with auto, or do I have to copy the temporary? |
Registered Member
|
Hi vitke,
an exact example which actually causes an issue would be great. At the moment, I can only suggest to remove the reference and refrain from using auto. You should in general refrain from using auto in context with Eigen. Almost every operation implemented in Eigen results in a template expression and the type behind your auto declared variable will be most surprising if you look at it. The expression templates also do not evaluate anything until they are assigned to a Matrix. The std::cout works with auto declared types because the implementation of the streaming operator calls .eval() on the dense expression you are passing which creates a temporary object which is finally evaluated. Regards, Hauke |
Registered Member
|
Hi Hauke, thanks for your reply. I cannot reproduce this in an isolated example and the whole code is 40,000+ lines, so I can't post an exact example.
This is probably related: I have two matrices R and psi of type Eigen::Matrix<double,3,3> and I do
If I print M it is uninitialized, if I run Valgrind it reports that M is uninitialized. If I write instead
then M is printed just fine and Valgrind does not complain. I understand that the exact type of a product is compicated, but uninitialized memory!? This does not sound like a template problem. And in the first example I had an opposite case - it was fine with auto and it wasn't fine if I specified the type. I can't see how could this possibly matter for memory initialization. If I print the same product in the following line
then everything is printed fine and there are no uninitialized numbers. This is most definitely a memory problem. |
Registered Member
|
Hi again,
the only suggestion I can give you then for now is once again to remove the reference (ampersamp) on your variable declarations. It makes no sense in the context you provided and is the only part of your code which looks a bit dodgy. Regards, Hauke |
Registered Member
|
Curiously, this happens only with g++-4.8.1. If I use g++-4.7.3 then it does not happen. Here is what gcc 4.8 release notes say:
Could these changes have introduced a bug in gcc? Is there a way to turn these optimizations off? My functions are not longer than a few hundred lines, but they are mostly inline, so I suppose that at some point in the compilation process a single huge function is created. |
Moderator
|
Not realated at all, and the fact it's "working" with gcc 4.7 is just luck. I'm pretty sure valgrind will detect memory errors even with gcc 4.7. Your references makes no sense, recall that the type of "A*B" is a abstract representation of a matrix product which basically only stores references to A and B. The fact your code with references is compiling is due to internal implementation details. It won't compile with A+B.
|
Registered Member
|
Here is an isolated example:
I compile it with
The output is 1 6.9532e-310 6.94606e-310 6.94605e-310 6.9532e-310 6.94593e-310 6.94606e-310 0 0 6.94606e-310 1 6.9532e-310 6.94606e-310 6.94605e-310 6.9532e-310 6.94593e-310 6.94606e-310 0 0 6.94606e-310 2 3.11661e-317 6.94605e-310 3.11621e-317 2.07452e-317 4.94066e-324 2.07743e-317 3.11703e-317 9.88131e-324 6.94606e-310 The optimization is essential: with -O0 it's all right. Something similar also happens with g++ 4.7.3, but not with g++ 4.6.4. Valgrind gives many errors with g++ 4.8.1 and with g++ 4.7.3, but no errors with g++ 4.6.4. I tried it on three machines running Ubuntu and on one machine running Arch, with at least two different and not too old versions of Eigen, including a version two days old. Valgrind outputs are too long to be pasted here, and I can't find a way to attach them, but you will probably be able to generate them. |
Registered Member
|
Another example, with no reference: just replace
with
and add the compiler option -std=c++0x. Similar output is obtained. |
Registered Member
|
And let me just add: Valgrind does not detect memory errors, but it it repeats this error over and over:
|
Registered Member
|
And finally I understood what you were saying about references I understand that it makes no sense to write auto & A = B*C in Eigen context, but why it doesn't make sense to write Matrix<double,3,3> & A = B*C? If I ommit the reference, then the product is evaluated i.e. converted to Matrix and then copied to A. If I put the reference, then copy operation is not performed. Am I right?
|
Moderator
|
You're wrong. Matrix<double,3,3> & A = B*C is not correct because B*C is not a Matrix<double,3,3>. The fact it's compiling is because, internally, B*C stores a Matrix<double,3,3> in the case it is plugged into a more complex expression and needs to be evaluated into a temporary. So at the end, A is storing a reference to an object that is deleted right after this statement, and A becomes invalid. The correct way is to write:
Matrix<double,3,3> A = B*C ; and thanks to expression templates, there is no temporary or extra copy at all. |
Registered Member
|
OK, I will omit the reference. But I think such behavior violates the standard (§12.2):
Thus the lifetime of a temporary to which a reference is bound should be extended for the lifetime of that reference. |
Registered Member
|
The standard gives the following example:
and later it says
So what is the difference with that case and our case? A constant reference is bound to an expression result in both cases. |
Registered Member
|
I think I understand: the standard says
So since the Eigen matrix expression result is not a matrix, it has to be converted by implicitly calling the eval function, the result of which is a temporary to which I bind my reference. But this temporary is destroyed. It does not violate the standard, although it violates my intuition. Thanks for opening my eyes! |
Moderator
|
hm, ok so it might still persists but it won't be initialized anyway. This is coherent with what valgrind told you. In the future this won't compile at all. |
Registered users: Bing [Bot], Google [Bot], Yahoo [Bot]