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 );