官方文档:Eigen: Using STL Containers with Eigen
"fixed-size vectorizable"固定大小、可向量化是指: if it has fixed size and that size is a multiple of 16 bytes.
Examples include:
Passing objects by value is almost always a very bad idea in C++, as this means useless copies, and one should pass them by reference instead.
With Eigen, this is even more important: passing fixed-size vectorizable Eigen objects by value is not only inefficient, it can be illegal or make your program crash! And the reason is that these Eigen objects have alignment modifiers that aren't respected when they are passed by value.(使用Eigen objects作为函数参数时,不可采用值传递)
For example, a function like this, where v
is passed by value:
void my_function(Eigen::Vector2d v);
//needs to be rewritten as follows, passing v by const reference:
void my_function(const Eigen::Vector2d& v);
Likewise if you have a class having an Eigen object as member:
struct Foo
{
Eigen::Vector2d v;
};
//void my_function(Foo v);
//This function also needs to be rewritten like this:
void my_function(const Foo& v);
Note that on the other hand, there is no problem with functions that return objects by value.(返回值可采用值传递Eigen objects)
Using STL containers on fixed-size vectorizable Eigen types, or classes having members of such types, requires taking the following two steps:
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.
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 locations(告诉容器使用一个分配器,它总是在16字节对齐的位置分配内存). Fortunately, Eigen does provide such an allocator: Eigen::aligned_allocator.
For example, instead of
-- std::map
you need to use
-- std::map
Note that the third parameter "std::less
The situation with std::vector was even worse (explanation below) so 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
Here is an example:
#include
/* ... */
std::vector >
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::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
Here is an example:
#include
/* ... */
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix2d)
std::vector
Explanation: The resize() method of std::vector takes a value_type argument (defaulting to value_type()). So with std::vector
If you define a structure having members of fixed-size vectorizable Eigen types, you must overload its "operator new" so that it generates 16-bytes-aligned pointers. Fortunately, Eigen provides you with a macro EIGEN_MAKE_ALIGNED_OPERATOR_NEW that does that for you.
(重载其“操作符new”,以便生成16字节对齐的指针, Eigen提供宏EIGEN_MAKE_ALIGNED_OPERATOR_NEW来实现)
The kind of code that needs to be changed is this:
class Foo
{
...
Eigen::Vector2d v;
...
};
...
Foo *foo = new Foo;
In other words: you have a class that has as a member a fixed-size vectorizable Eigen object, and then you dynamically create an object of that class.
Very easy, you just need to put a EIGEN_MAKE_ALIGNED_OPERATOR_NEW macro in a public part of your class, like this:
class Foo
{
...
Eigen::Vector2d v;
...
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW //这个宏使“new Foo”总是返回一个对齐的指针
};
...
Foo *foo = new Foo;
This macro makes "new Foo" always return an aligned pointer.
If this approach is too intrusive, see also the other solutions.
Dynamic-size matrices and vectors, such as Eigen::VectorXd, allocate dynamically their own array of coefficients, so they take care of requiring absolute alignment automatically. So they don't cause this issue. The issue discussed here is only with fixed-size vectorizable matrices and vectors.
No, it's not our bug. It's more like an inherent problem of the C++98 language specification, and seems to be taken care of in the upcoming language revision: see this document.
For this situation, we offer the macro EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign). It will generate aligned operators like EIGEN_MAKE_ALIGNED_OPERATOR_NEW if NeedsToAlign is true. It will generate operators with the default alignment if NeedsToAlign is false.
示例:
template class Foo
{
typedef Eigen::Matrix Vector;
enum { NeedsToAlign = (sizeof(Vector)%16)==0 };
...
Vector v;
...
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign)
};
...
Foo<4> *foo4 = new Foo<4>; // foo4 is guaranteed to be 128bit-aligned
Foo<3> *foo3 = new Foo<3>; // foo3 has only the system default alignment guarantee