使用Eigen庫時需注意的一些問題

官方文檔:http://eigen.tuxfamily.org/dox-devel/group__TopicStlContainers.html

The issue discussed here is only with fixed-size vectorizable matrices and vectors.

"fixed-size vectorizable"固定大小、可向量化是指: if it has fixed size and that size is a multiple of 16 bytes.

Examples include:

 

1.Passing Eigen objects by value to functions

      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)

 

2.Using STL Containers with Eigen

       Using STL containers on fixed-size vectorizable Eigen types, or classes having members of such types, requires taking the following two steps:

  • A 16-byte-aligned allocator must be usedEigen does provide one ready for use: aligned_allocator.
  •                                             ----必須使用16字節的對齊分配器
  • If you want to use the std::vector container, you need to #include <Eigen/StdVector>.
  •                                             ----- #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 locations(告訴容器使用一個分配器,它總是在16字節對齊的位置分配內存). Fortunately, Eigen does provide such an allocator: Eigen::aligned_allocator.

    For example, instead of

-- std::map<int, Eigen::Vector4f>

    you need to use

-- std::map<int, Eigen::Vector4f, std::less<int>, Eigen::aligned_allocator<std::pair<const int, Eigen::Vector4f> > >

     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

      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 <Eigen/StdVector>.

Here is an example:

#include<Eigen/StdVector>

/* ... */

std::vector<Eigen::Vector4f,Eigen::aligned_allocator<Eigen::Vector4f> >

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::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>

/* ... */

EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix2d)

std::vector<Eigen::Vector2d>

Explanation: The resize() method of std::vector takes a value_type argument (defaulting to value_type()). So with std::vector<Eigen::Vector4f>, some Eigen::Vector4f objects will be passed by value, which discards any alignment modifiers, so a Eigen::Vector4f 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::Vector4f, that is able to deal properly with this situation.

 

3.Structures Having Eigen Members

Executive Summary

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來實現)

What kind of code needs to be changed?

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.

How should such code be modified?

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.

What about dynamic-size matrices and vectors?

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.

So is this a bug in Eigen?

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.

What if I want to do this conditionnally (depending on template parameters) ?

根據模板參數,動態配置:

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<int n> class Foo
{
typedef Eigen::Matrix<float,n,1> 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

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章