与std :: vector的对齐问题

时间:2017-11-18 09:04:56

标签: c++ vector eigen

我终于遇到了这里描述的恼人问题: https://eigen.tuxfamily.org/dox/group__TopicStlContainers.html

我有一个包含几个Eigen固定大小矩阵的结构,我想在std :: vector中存储我的结构的几个实例。所以很明显'这些问题只出现在固定大小的可矢量化特征类型和具有这种特征对象作为成员的结构中。适用。然而,它仅描述了如何使用直接收集特征对象的向量来解决问题,而不是使用包含特征实例的结构。

目前我的问题如下:

struct MyStruct{
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW //Don't know if this applies here
    Eigen::Matrix<double, 4, 4> A;
    // several more instances and stuff here
    MyStruct ( ...)  // constructor taking several arguments, but only running an initilization list for some members

    // no destructor defined / implemented !

    // no methods!
}

//
MyStruct instanceStruct( .. constructing .. );
instanceStruct.A = someAssigment() ; 
// this type of 'instancing' before i push it into the vector is necessary ...

std::vector<MyStruct> myVector;
myVector.push_back( std::move( instanceStruct ) ); // gdb tells me that here we run into a SIGSEGV

导致问题的原因是什么?谢谢!

1 个答案:

答案 0 :(得分:1)

来自

上的C ++ 17

标准容器使用的默认分配器需要遵守对齐,因此任何存储持续时间(*)的变量也是如此。因此,在这种情况下,您的代码应该是开箱即用的,因为Eigen会在需要时指定对齐。

(*)但警告

  • 实现可能仍会抛出bad_alloc或拒绝编译请求不受支持的对齐的定义。但是,据我所知,它不能无声地失败,也不会导致未定义的行为。

  • 允许用户定义的分配器以静默方式忽略过度对齐的类型。此外,请注意,前C ++ 17库可能会在内部进行假设,从而避免上述保证。通常,您应该始终检查任何设施分配类型(可能是内部)的过度对齐类型支持。

来自

上的C ++ 11

您应该担心的唯一(*)事项是通过new或默认分配器获得的动态存储持续时间的变量(有关详细信息,请参阅P0035r4)。

现在,Eigen通过提供EIGEN_MAKE_ALIGNED_OPERATOR_NEW和 本征:: aligned_allocator:

struct MyStruct{
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW // this will make new MyStruct to work
//...

// this will make vector (or any other allocator-aware container) to work
std::vector<MyStruct,Eigen::aligned_allocator<MyStruct> >

请注意,与官方文档所说的相反,您可以在C ++ 11中使用任何对齐的分配器,因此不需要#include<Eigen/StdVector>(如果在C ++之前编译,则必须包含它)虽然模式,或者你的编译器不完全支持c ++ 11对齐语义)。

或者,您可以禁用矢量化(请参阅Eigen宏文档以了解如何)或仅通过new分配矢量化矩阵:

struct MyStructImpl{
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
    // vectorizable matrices ...
};

struct MyStruct
{
  MyStructImpl* aligned_data_; // possibly a unique_ptr<MyStructImpl>
  // copy-move-assign accordingly ...
  // non-vectorizable matrices and other data ...
};

std::vector<MyStruct> v; // ok !

这将花费你的堆分配和更少的内存位置,但移动MyStruct会更便宜。因此,根据您的使用情况,它可能会更快或更慢。