1. 程式人生 > >Eigen庫資料結構記憶體對齊問題

Eigen庫資料結構記憶體對齊問題

我這裡講的是在用到開源庫Eigen中的資料結構時會出現這樣的錯誤
error C2719: 't': formal parameter with __declspec(align('16')) won't be aligned
意思就是t: 具有 __declspec(align('16')) 的形參將不被對齊
還有一種錯誤的提示就是:
Assertion failed: (reinterpret_cast<size_t>(array) & 0xf) == 0 && "this assertion is explained here: http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" " **** READ THIS WEB PAGE !!! ****", file c:\eigen3.2.7\eigen\src\core\densestorage.h, line 86


導致上述兩個錯誤的原因是因為Eigen庫為了使用SSE加速,所以記憶體分配上使用了128位的指標。如果大家覺得我說的不夠詳細,也可以去Eigen網站裡去看英文的解釋。這裡我只講下面的三種情況,因為在我的程式碼中這三種情況都涉及到了,所以也專門看了網站上的解決方法

  • Structures having Eigen objects as members
  • STL Containers
  • Passing Eigen objects by value
    上面三種情況的意思就是Eigen庫中的資料結構作為自定義的結構體或者類中的成員STL容器含有Eigen的資料結構Eigen資料結構作為函式的引數

    另外的一種情況我沒有遇到過,所以也就不詳細敘述了,本人也沒有仔細的去看,如果我有時間看了,我會把解決方法也貼出來。
  • Compiler making a wrong assumption on stack alignment (for instance GCC on Windows)

Structures having Eigen objects as members

官方給的例子是如果你的程式碼是下面這個樣子的,在你自定義的類中,成員中有Eigen的資料結構,

class Foo
{
  //...
  Eigen::Vector2d v;
  //...
};
//...
Foo *foo = new Foo();

這個錯誤比較難發現,因為它在編譯的時候是不會提示有錯誤的,只會在執行的時候提示出錯,錯誤的提示就是Assertion failed: (reinterpret_cast<size_t>(array) & 0xf) == 0 && "this assertion is explained here: " "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" " **** READ THIS WEB PAGE !!! ****", file c:\eigen3.2.7\eigen\src\core\densestorage.h, line 86
這是因為你在使用這個類的時候用到了new方法,這個方法是開闢一個記憶體,但是呢在上面的程式碼中沒有自定義建構函式,所以在new的時候會呼叫預設的建構函式,呼叫預設的建構函式的錯誤在於記憶體的位數不對齊,所以會導致程式執行的時候出錯。 解決的方法就是在類中加入巨集EIGEN_MAKE_ALIGNED_OPERATOR_NEW, 如下:

 class Foo
{
  ...
  Eigen::Vector2d v;
  ...
public:
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};

通過查詢這個巨集,我們可以找到這樣一句程式碼#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign),大致意思就是指標對齊。
大家可以自己新建一個控制檯程式來驗證上述的解決方案是否對。很簡單的程式碼,copy一下就可以了。本人已經試驗了,可以完美解決上述的錯誤。

STL Containers

如果STL容器中的元素是Eigen庫資料結構,例如這裡定義一個vector容器,元素是Matrix4d ,如下所示:

vector<Eigen::Matrix4d>;

這個錯誤也是和上述一樣的提示,編譯不會出錯,只有在執行的時候出錯。解決的方法很簡單,定義改成下面的方式:

vector<Eigen::Matrix4d,Eigen::aligned_allocator<Eigen::Matrix4d>>;

其實上述的這段程式碼才是標準的定義容器方法,只是我們一般情況下定義容器的元素都是C++中的型別,所以可以省略,這是因為在C++11標準中,aligned_allocator管理C++中的各種資料型別的記憶體方法是一樣的,可以不需要著重寫出來。但是在Eigen管理記憶體和C++11中的方法是不一樣的,所以需要單獨強調元素的記憶體分配和管理。

Passing Eigen objects by value

如果自定義的一個函式中的引數有Eigen資料型別,對於這個引數需要特別的注意,大多數情況下,我們學習的C++相關的書中,函式和引數的定義如下:

FramedTransformation( int id, Eigen::Matrix4d t );

這個錯誤會在你編譯的時候提示你錯誤,錯誤的資訊是error C2719: 't': formal parameter with __declspec(align('16')) won't be aligned
要解決這個錯誤也是很簡單的,只有我們把引數t的型別稍加變化即可。如下:

FramedTransformation( int id, const Eigen::Matrix4d& t );