Search code examples
c++eigeneigen3

What happens to unassigned `Eigen::VectorXd` object following a call to `segment()`?


I have a class Foo that stores Eigen MatrixXd and VectorXd of matching dimensions and offers a simple function .mult() that performs matrix-vector multiplication. And I have a function that calls mult(), takes a segment of the returned vector, and does some further computation. Here is a simplified version of the code:

#include <Eigen/Dense>

class Foo {
  Eigen::MatrixXd X;
  Eigen::VectorXd v;
public:
  Foo() {
    X.resize(2, 2);
    v.resize(2);
    X << 1, 4, 2, 4;
    v << -1, 1;
  }
  Eigen::VectorXd mult() {
    return X * v;
  }
};

Eigen::VectorXd bar() {
  Foo f;
  Eigen::VectorXd val = f.mult().segment(1, 1);
// Use val to do some computation.
  Eigen::VectorXd ret = val.array() + 2;
  return ret;
}

During a code review, a comment was raised that this could lead to dangling reference of the unnamed/temp variable that stores the result of f.mult(). And a general question was raised regarding the lifetime of temporary variables that aren't assigned a name.

If I understand RVO correctly, a temporary object will be created on the stack whose address will be passed to f.mult(), which will then store the result of X * v to the passed in memory address. And this temporary object will go out of scope when bar() terminates. There shouldn't be any dangling reference or concerns regarding the scope of the temporary and unassigned variable. But I'm not so sure.

Eigen is an elegant but a complex library and I hope to ensure that I'm using it in safely as possible. Thanks in advance!


Solution

  • What you are doing is save (but inefficient).

    f.mult() returns a Eigen::VectorXd object by value which exist for the rest of the statement ("until the next ;"). So calling segment() on it is safe, as long as you store that result into a VectorXd (and not into an auto object).

    To get a segment of a matrix-vector product it would however be more efficient to just multipy the corresponding sub-block of the matrix, i.e.:

    (X*v).segment(a,b) == X.rows(a,b) * v