Home > front end >  Returning Eigen matrices and temporaries
Returning Eigen matrices and temporaries

Time:12-22

Consider the following function Foo:

// ...

Eigen::Vector3d Foo() {
    Eigen::Vector3d res;
    // ...
    return res;
}

int main () {
    Eigen::VectorXd foo = Foo();    // (1)
    return 0;
}

The line (1) should not create any temporaries due to return value optimization. But consider the following case:

// ...

int main () {
    Eigen::VectorXd foo;
    // ...
    foo.head<3>() = Foo();    // (2)
    return 0;
}

Does (2) create any temporaries? More generally, does initializing any block of a matrix as in (2) create any temporaries? It would be great if this were not the case. Otherwise, I could redefine Foo as follows:

// ...

void AlternativeFoo(Eigen::Ref<Eigen::Vector3d> res) {
    // Modify res
}

int main () {
    Eigen::VectorXd foo;
    // ...
    AlternativeFoo(foo.head<3>());    // (3)
    return 0;
}

Is (3) the only way to achieve the above without creating temporaries?

CodePudding user response:

The line (1) should not create any temporaries due to return value optimization.

No, it must materialize a temporary for the return value of Foo.

The return type of Foo and the type of the variable foo do not match (up to cv-qualification): Vector3d vs VectorXd.

But this is a necessary condition for copy elision to be allowed. If that is not the case, the constructor used will be neither a copy nor a move constructor in the first place.

So elision doesn't happen and in the constructor that is going to be called, the return value of Foo is bound to a reference argument, which will cause materialization of the temporary.

Does (2) create any temporaries? More generally, does initializing any block of a matrix as in (2) create any temporaries?

Yes, again temporaries for the Foo return values will be materialized, this time caused by binding to reference parameters in the operator=.

Is (3) the only way to achieve the above without creating temporaries?

I would assume so, but it probably doesn't matter anyway. Assuming Foo can be inlined, the distinction is likely going to become meaningless and the compiler will figure out if the operations in Foo can be performed directly on the storage of foo or not.

If Foo cannot be inlined, then copying the three entries of the vector is unlikely to have significant relevance against the function call. Your alternative solution would in this case force extra indirection, which may be more costly than copying a few values as well.

  • Related