Registered Member
|
In the lazy evaluation documentation, it says aliasing is something to worry about, except from operator *.
However, I think that there is another issue - temporal(rvalue) lifetime scope. Consider this code:
The reason I worry is because foo() return object is temporal value(prvalue), and it's lifetime scope ends up after lazy evaluation creation. According to C++, const reference(i.e. const T&) to temporal(rvalue) objects extend the lifetime of the object to this const reference lifetime. However, if I understood correctly, lifetime isn't extended even longer if this const reference is given to another const reference. Because of that, I think that this is another issue with lazy evaluation. Am I right? |
Registered Member
|
I found source to my claim:
http://bytes.com/topic/c/answers/806030 ... t-lifetime Is this problem known? Haven't found it in docs |
Registered Member
|
I don't think that the link you have posted is related to your code example. In that link, the problem that occurs is that a reference to a member of a temporary object is used. Note that usage of a const reference for the member doesn't help you in that case: while a const reference can extend the lifetime of a temporary variable, this const reference is not related to the original temporary object whose lifetime thus ends immediately after the line Bar().GetFoo(); Consequently, the reference to its member also becomes invalid immediately after hat line.
In your code example, const references are created that are directly linked to the temporary object returned by foo() and thus extend the object's lifetime until the entire line Matrix2d result = foo() + a; has been processed. |
Moderator
|
As jaschau_ wrote, there is no problem with your code snippet, however there do exist other pitfalls as mentioned there:
http://eigen.tuxfamily.org/index.php?ti ... _templates Another one based on your example would be to declare 'result' using auto: auto result = foo() + a; In that case the variable 'result' will reference a dead object. |
Registered Member
|
Thanks for your response!
I run my example code and it works fine as you mentioned. But I still don't understand why it's working. Here is what I think that happens: 1. calculate foo() 2. create a CwiseBinaryOp with constructor (left, right, functor) 2. a. initialize the "left" constructor reference to foo() value and extend it lifetime to the constructor lifetime b. initialize the "right" reference and "functor" (not important here) c. call the constructor c. 1. inside the constructor, initialize the "left" member reference with "left" parameter reference. ... 3. call "result" constructor with the CwiseBinaryOp. Now what you said is that initialize a reference with temporary extends the temporary lifetime to this reference scope. However, the reference scope is the constructor, NOT the object. After that this parameter reference is initialize, initializing the member reference doesn't extend(so I think) the temporary lifetime again. Think of this logic like this: Suppose CwiseBinaryOp constructor wouldn't be inlined in the header, and the implementation was in external cpp unit. How could the compiler know that the reference that was given in the CwiseBinaryOp constructor is used as a member reference? (in order to extend lifetime to that CwiseBinaryOp object) Whether this constructor is inlined or not, shouldn't change the C++ rules on lifetime scopes. So I guess you right, but I still don't know why. Any idea? |
Moderator
|
Nope, in your example, the temporary returned by foo() is pushed on the stack and its lifetime is extended to whole statement. You can check by yourself:
|
Registered Member
|
I've looked again at this template class and on the internal:nested. I understand that the template argument for temporary object isn't const T& but T(or maybe T&& in C++x0), and T& or const T& for lvalues. I see now why you're genius Thank you very much! |
Registered users: bartoloni, Bing [Bot], Google [Bot], Yahoo [Bot]