Using STL Containers with Eigen

Executive summary

If you're compiling in [c++17] mode only with a sufficiently recent compiler (e.g., GCC>=7, clang>=5, MSVC>=19.12), then everything is taken care by the compiler and you can stop reading.

Otherwise, using STL containers on fixed-size vectorizable Eigen types, or classes having members of such types, requires the use of an over-aligned allocator. That is, an allocator capable of allocating buffers with 16, 32, or even 64 bytes alignment. Eigen does provide one ready for use: aligned_allocator.

Prior to [c++11], if you want to use the std::vector container, then you also have to #include <Eigen/StdVector> .

These issues arise only with fixed-size vectorizable Eigen types and structures having such Eigen objects as member. For other Eigen types, such as Vector3f or MatrixXd, no special care is needed when using STL containers.

Using an aligned allocator

STL containers take an optional template parameter, the allocator type. When using STL containers on fixed-size vectorizable Eigen types, you need tell the container to use an allocator that will always allocate memory at 16-byte-aligned (or more) locations. Fortunately, Eigen does provide such an allocator: Eigen::aligned_allocator.

For example, instead of

std::map<int, Eigen::Vector4d>

you need to use

std::map<int, Eigen::Vector4d, std::less<int>,
STL compatible allocator to use with types requiring a non-standard alignment.
Definition: Memory.h:958

Note that the third parameter std::less<int> is just the default value, but we have to include it because we want to specify the fourth parameter, which is the allocator type.

The case of std::vector

This section is for c++98/03 users only. [c++11] (or above) users can stop reading here.

So in c++98/03, the situation with std::vector is more complicated because of a bug in the standard (explanation below). To workaround the issue, we had to specialize it for the Eigen::aligned_allocator type. In practice you must use the Eigen::aligned_allocator (not another aligned allocator), and #include <Eigen/StdVector>.

Here is an example:

#include<Eigen/StdVector>
/* ... */
std::vector<Eigen::Vector4f,Eigen::aligned_allocator<Eigen::Vector4f> >

Explanation: The resize() method of std::vector takes a value_type argument (defaulting to value_type()). So with std::vector<Eigen::Vector4d>, some Eigen::Vector4d objects will be passed by value, which discards any alignment modifiers, so a Eigen::Vector4d can be created at an unaligned location. In order to avoid that, the only solution we saw was to specialize std::vector to make it work on a slight modification of, here, Eigen::Vector4d, that is able to deal properly with this situation.

An alternative - specializing std::vector for Eigen types

As an alternative to the recommended approach described above, you have the option to specialize std::vector for Eigen types requiring alignment. The advantage is that you won't need to declare std::vector all over with Eigen::aligned_allocator. One drawback on the other hand side is that the specialization needs to be defined before all code pieces in which e.g. std::vector<Vector2d> is used. Otherwise, without knowing the specialization the compiler will compile that particular instance with the default std::allocator and you program is most likely to crash.

Here is an example:

#include<Eigen/StdVector>
/* ... */
std::vector<Eigen::Vector2d>
#define EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(...)
Definition: StdVector.h:25
Matrix< double, 2, 2 > Matrix2d
2×2 matrix of type double.
Definition: Matrix.h:502