Move semantics in Eigen
Asked Answered
A

1

7

I have couple of question about Eigen:

  1. Does anyone know if there is any plan to support move semantics in Eigen anytime soon? Couldn't find anything on the TODO list of the Eigen3 web page. Right now I am using the swap trick to get rid of temporaries, like

    MatrixXd foo()
    {
        MatrixXd huge_matrix(N,N); // size N x N where N is quite large
        // do something here with huge_matrix
        return huge_matrix; 
    }
    
    MatrixXd A(N, N); 
    A.swap(foo());
    

    I'd very much like to write the above swap line in a C++11 style like

    A = foo();
    

    and not to have to worry about the temporary returned by foo().

  2. Can a C++98/C++03 compiler optimize the code A = foo(); to get rid of this temporary? Or the safest bet is to use swap()?
Athamas answered 16/11, 2014 at 17:25 Comment(0)
I
8

Copy elision will do the job just fine. Even a C++03 compiler will elide the temporary.
In particular, NRVO (named return value optimization) will, for this code,

MatrixXd foo()
{
    MatrixXd huge_matrix(N,N);
    return huge_matrix; 
}

MatrixXd A = foo();

construct huge_matrix right inside A. The C++03 standard specifies in [class.copy]/15:

This elision of copy operations is permitted in the following circumstances (which may be combined to eliminate multiple copies):

  • in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object with the same cv-unqualified type as the function return type, the copy operation can be omitted by constructing the automatic object directly into the function’s return value
  • when a temporary class object that has not been bound to a reference (12.2) would be copied to a class object with the same cv-unqualified type, the copy operation can be omitted by constructing the temporary object directly into the target of the omitted copy
Incurable answered 16/11, 2014 at 17:30 Comment(7)
Thanks, wasn't sure about this. In particular, my foo takes A as a param by const reference, so basically I have something like A = foo(A). Copy elision should work even in this case, as the as-if rule is satisfied, is this correct?Athamas
In my code snippet, it seems that copy elision is indeed performed by the copy ctor, in a line like MatrixXd A = foo(). However, it is NOT performed by the assignment operator, whenever I reuse A such as A = foo();, and I pass by value to the assignment operator.Athamas
Ohh I see why, because I was using a cout in the assignment operator, and this have observable effect, so it is not elided (although copy ctors are) https://mcmap.net/q/823528/-is-default-constructor-elision-assignment-elision-possible-in-principleAthamas
@Athamas .. in an assignment like this, the move assignment operator should be invoked. And return value optimization is done as well, constructing the local object into the return value temporary. So the total cost should be one move assignment.Incurable
I know, move semantics does it, but the question was what happens if I use pre-C++11. And it's still not clear (at least I cannot verify) if the assignment operator is elided or not, since if I put a cout into it, it won't be, see the link above.Athamas
@Athamas If you do this assignment in C++03, then you should implement the assignment operator via copy&swap. That way copy elision can be performed twice: Once for the copy of the return value into the temporary and once for the copy of the temporary into the parameter of the assignment operator. Then the only cost is the swap. (And no, the assignment operator call cannot be elided.)Incurable
Ok, many thanks, I just have to see how Eigen implements the assignment, probably via copy-and-swap, as it is the least error-prone way. But according to the link I posted, it seems that even assignment operator can be elided, am I missing something here? Or is it elided only in the case when it is trivial, like a default one?Athamas

© 2022 - 2024 — McMap. All rights reserved.