【问题标题】:Alignment issues with std::vectorstd::vector 的对齐问题
【发布时间】:2018-05-02 00:53:14
【问题描述】:

我终于遇到了这里描述的烦人问题: 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

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

【问题讨论】:

  • 你用的是什么编译器? AFAIK,在 c++17 中,一切应该开箱即用,没有 EIGEN_MAKE_ALIGNED_OPERATOR_NEW 之类的......
  • gcc 7.2 (arch linux),带有 -march=native。没有 -march=native,(因此,没有矢量化),一切正常
  • 好的,但是你试过“-std=c++17”吗?
  • 行得通,谢谢!但是,我能为 C++11 标准做什么?
  • 在 c++11 中,您需要使用特征提供的分配器及其特征提供的向量特化。这很丑,我知道。要么,要么禁用矢量化,要么将 MyStruct 作为 unique_ptr 存储在另一个结构中,然后您可以将其传递给矢量...即便如此,您仍然需要特别注意在复制特征对象时避免 UB ...我会稍后写一个更详细的答案...

标签: c++ vector eigen


【解决方案1】:

从 C++17 开始

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

(*) 有 警告

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

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

从 C++11 开始

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

现在,Eigen 通过提供 EIGEN_MAKE_ALIGNED_OPERATOR_NEW 和 Eigen::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&lt;Eigen/StdVector&gt;(如果在 C++11 之前的模式下编译,则必须包含它,或者如果您的编译器不完全支持 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 会更便宜。因此,结果可能更快或更慢,具体取决于您的用例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-29
    • 2023-03-21
    • 2015-04-08
    • 1970-01-01
    • 2012-10-08
    • 2011-01-19
    相关资源
    最近更新 更多