为什么在改变std::vector的分配器时初始化列表不可用?

Why are initializer lists not available when changing the allocator of std::vector?

本文关键字:初始化 列表 分配器 改变 std vector 为什么      更新时间:2023-10-16

在我的项目中,我将使用的点类型从Eigen::Vector2f更改为Eigen::Vector2d,并遇到对齐问题。

下面是代码的简化版本:

#include <vector>
#include <Eigen/Eigen>
int main()
{
    std::vector<Eigen::Vector2d> points = { {0,0}, {0,1} };
}

我得到以下运行时错误:

eigen3/Eigen/src/Core/DenseStorage.h:78: Eigen::internal::plain_array<double, 2, 0, 16>::plain_array() [T = double, Size = 2, MatrixOrArrayOptions = 0, Alignment = 16]: Assertion `(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 !!! ****"' failed.

正如断言消息所建议的那样,我了解了固定大小的可向量化特征对象所需的对齐方式。还有关于STL容器的小节。我似乎有两个选择:

  1. 使用Eigen::aligned_allocator
  2. 或使用EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION宏。

两个尝试都不能编译(在GCC 4.8.3和Clang 3.5中测试),因为编译器不能正确转换初始化项列表。

修改后的代码:

#include <vector>
#include <Eigen/Eigen>
#include <Eigen/StdVector>
// EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Eigen::Vector2d)
int main()
{
    std::vector<Eigen::Vector2d, Eigen::aligned_allocator<Eigen::Vector2d>> points = { {0,0}, {0,1} };
    // std::vector<Eigen::Vector2d> points = { {0,0}, {0,1} };
}

GCC错误输出

error: could not convert ‘{{0, 0}, {0, 1}}’ from ‘<brace-enclosed initializer list>’ to ‘std::vector<Eigen::Matrix<double, 2, 1>, Eigen::aligned_allocator<Eigen::Matrix<double, 2, 1> > >’

所以我想知道:

  • 为什么在更改std::vector的分配器时初始化列表不可用?

    • 这是因为对齐吗?
    • 我能以某种方式对齐初始化列表吗?
  • 为什么专门化版本失败?

    • 这些是否缺少初始化列表功能?

在研究了Eigen/StdVector包含文件(确切地说,它是在版本3.2.1的Eigen/src/StlSupport/StdVector.h第68行)之后,似乎问题源于此头文件中std::vector的部分模板专门化。一旦使用Eigen::aligned_allocator作为分配器,这个部分模板专门化就会替换STL vector。而且这种专门化似乎缺少c++ 11的特性。

除了替换分配器之外,详细说明为什么需要这个专门化:在c++ 11之前,std::vector的resize函数可以接受一个附加形参来初始化新创建的元素。根据Eigen3文档,按值传递参数将丢弃任何对齐修饰符,并且不能用于固定大小的可向量化特征对象(参见SIMD)。

编辑:

经过更多的测试,我意识到std::vector的c++ 11实现没有上述问题。因此,要解决对齐问题,您只需填写Eigen::aligned_allocator。但是不包含Eigen/StdVector。包含此文件将阻止您使用std::vector的c++ 11实现,因为此头文件定义了Eigen::aligned_allocator作为分配器的部分专门化。