Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

`std::move` an Eigen object in a constructor?

Tags:

c++

eigen

eigen3

The Eigen3 documentation warns against passing Eigen objects by value, but they only refer to objects being used as function arguments.

Suppose I'm using Eigen 3.4.0 and C++20. If I have a struct with an Eigen member, does this mean I can't std::move a pass-by-value in the constructor? Do I need to pass-by-reference and copy the object? Or is this handled somehow by modern move-semantics?

If I can't std::move Eigen objects in a constructor, does this mean I should explicitly delete the move-constructors from my struct?

For example,

#include <utility>
#include <Eigen/Core>

struct Node {
  Eigen::Vector3d position;
  double temperature;

  // is this constructor safe to use?
  Node(Eigen::Vector3d position_, const double temperature_)
    : position(std::move(position_)), temperature(temperature_) {}

  // or must it be this?
  Node(const Eigen::Vector3d& position_, const double temperature_)
    : position(position_), temperature(temperature_) {}

  // also, should move-constructors be explicitly deleted?
  Node(Node&&) = delete;
  Node& operator=(Node&&) = delete;
};
like image 734
NickFP Avatar asked Sep 14 '25 21:09

NickFP


1 Answers

There is nothing magic about Eigen objects. Fixed sized types such as Vector3d behave like std::array. Dynamic sized types like VectorXd behave like std::vector.

Pass-by-value for a dynamic sized type typically is a mistake because it usually invokes a copy construction which can be very expensive for large matrices. Pass-by-reference (const, lvalue, rvalue) is almost always the right choice [footnote 1].

Pass-by-value for fixed-sized types can be a benefit because the first few arguments are usually passed in registers (depending on the platform). This avoids spilling values to the stack. However, this doesn't work for Eigen. I assume they declare a destructor, even if they don't need one. That turns any pass-by-value into pass-by-reference to a hidden copy. You can see this in godbolt. This seems like a missed optimization in Eigen.

In conclusion: Use pass-by-reference. Move-construction makes sense for dynamic sized eigen arrays. It makes no difference for fixed sized types.

Footnote 1: A rare exception can be cases were you would need to do a copy anyway inside the function.

like image 135
Homer512 Avatar answered Sep 17 '25 11:09

Homer512