参考资料:
在Eigen库的使用过程在经常出现类似这样的问题:
/usr/include/eigen3/Eigen/src/Core/DenseStorage.h:128: Eigen::internal::plain_array<T, Size, MatrixOrArrayOptions, 32>::plain_array() [with T = float; int Size = 8; int MatrixOrArrayOptions = 0]: Assertion `(reinterpret_cast<size_t>(eigen_unaligned_array_assert_workaround_gcc47(array)) & (31)) == 0 && "this assertion is explained here: " "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" " **** READ THIS WEB PAGE !!! ****"' failed.
原因是因为Eigen库使用了SSE加速,需要按照128位进行对齐,这导致了Fixed-size vectorizable Eigen objects必须是16字节对齐,一般Eigen已经做好了对齐,例如Eigen库重载了new操作,然而有些情况这写对齐设置被覆盖了,造成了上述断言错误。
如果你不需要Eigen的加速,使用以下三种方法,可以解决这类错误:
使用不对齐对象:Eigen中对象提供了多种构造函数,使用不对齐的构造函数构造对象。
使用Eigen_DONT_VECTORIZE宏:这禁止了所有16字节静态对齐代码
同时使用 Eigen_DONT_VECTORIZE和EIGEN_DISABLE_UNALIGNED_ASSERT宏:这保留16字节对齐代码,但禁止了向量化
否则,根据以下情况:
1.程序中有类包含Eigen对象,例如:
classFoo
{
//...
Eigen::Vector2d v; //Fixed-size vectorizable Eigen objects
//...
};
//...
Foo *foo = new Foo;
我们要改为:
class Foo
{
Eigen::Vector2d v;
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW //此处添加宏定义
};
Foo *foo = new Foo;
2.STL容器或者手动内存分配
像std::map/std::vector重包含Eigen对象,例如
std::vector<Eigen::Matrix2f> my_vector;
struct my_class { ... Eigen::Matrix2f m; ... };
std::map<int, my_class> my_map;
需要执行以下两步:
使用16位对齐的分配,Eigen提供了aligned_allocator
如果使用包含std::vector容器,需要包含 #include <Eigen/StdVector>头文件
std::map<int,Eigen::vector4f> 改为
std::map<int,Eigen::Vector4f,std::less<int>,
Eigen::aligned alocator<std::pair<const int,Eigen::vector4f>> >
#include<Eigen/StdVector>
std::vector<Eigen::vector4f,Eigen::aligned_allocator<Eigen::vector4f> >
另一种针对std::vector的解决方法,在所有使用vector的代码段前定义
#include<Eigen/StdVector>
/* ... */
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix2d)
std::vector<Eigen::Vector2d>
3.函数通过传值法传递Eigen对象
void func(Eigen::Vector4d v);
需要改为传址法:
void my_function(constEigen::Vector2d& v);
如果传递参数为包含Eigen对象的对象:
struct Foo
{
Eigen::Vector2d v;
};
void my_function(Foo v);
函数也要以传址形式传递参数
void my_function(const Foo& v);
4.编译器对堆栈对齐做错误假设(例如windows上的GCC)
这个问题在windows上GCC的GCC 4.5版本被修复。基本已经没有。
不幸的是,C ++不可能在编译时检测到任何前述的缺点(尽管静态分析器变得越来越强大,可以检测其中的一些)
即使在运行时,我们可以做也只是捕获无效的未对齐分配并触发本页开头提到的显式断言。
因此,如果您的程序在给定的系统上运行良好,并且有一些给定的编译标志,那么这不能保证您的代码是安全的。
例如,在大多数64位系统上,缓冲区在16字节边界上对齐,因此,如果不启用AVX指令集,则代码将运行良好。
另一方面,代码移动到另一个平台可能造成断言错误,或者使能AVX指令集(默认需要32位对齐)
网友评论