Alignment issues with std::vector

对着背影说爱祢 提交于 2021-01-05 03:30:55

问题


I finally ran into the annoying issue described here: https://eigen.tuxfamily.org/dox/group__TopicStlContainers.html

I have a structure containing several Eigen fixed-size matrices, and i want to store several instances of my structure in a std::vector. So obviously 'These issues arise only with fixed-size vectorizable Eigen types and structures having such Eigen objects as member.' applies. However, it is only described how to solve the issue with vectors directly collecting Eigen Objects, not with structures containing Eigen instances.

Currently my problem looks like this:

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

What causes the problem? Thank you!


回答1:


From C++17 on

The default allocator used by standard containers is required to respect alignment, and so are variables of any storage duration (*). Therefore, your code should work out-of-the-box in this case, because Eigen do specify alignment where needed.

(*) there are caveats though:

  • an implementation may still throw bad_alloc or refuse to compile definitions where an unsupported alignment is requested. But, as far as I know, it cannot fail silently, nor result in undefined behavior.

  • user defined allocators are allowed to silently ignore over-aligned types. Moreover, beware that pre-C++17 libraries may make assumptions internally, circumventing the aforementioned guarantees. In general, you should always check for over-aligned type support for any facility allocating types (possibly internally).

From C++11 on

The only(*) thing you should worry about are variables of dynamic storage duration obtained either via new or the default allocator (see P0035r4 for more details).

Now, Eigen fixes both by providing EIGEN_MAKE_ALIGNED_OPERATOR_NEW and 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> >

note that, contrary to what the official doc says, you can use any aligned allocator in C++11, so there's no need to #include<Eigen/StdVector> (you must include it if compiling in pre-C++11 mode though, or if your compiler does not fully support c++11 alignment semantics).

Alternatively, you can disable vectorization (see Eigen macro doc to see how) or allocate vectorizable matrices only via 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 !

this will cost you an heap allocation and less memory locality, but will make cheaper to move MyStruct around. So, it may turn out faster or slower, depending on your use case.



来源:https://stackoverflow.com/questions/47364311/alignment-issues-with-stdvector

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!