如何将带有自定义分配器的 std::vector 传递给需要带有 std::allocator 的函数?

How to pass an std::vector with custom allocator to a function that expects one with std::allocator?

我正在使用外部库 (pcl),因此我需要一个不会更改现有函数原型的解决方案。

我正在使用的一个函数生成一个 std::vector<int, Eigen::aligned_allocator<int>>。我接下来要调用的函数需要 const boost::shared_ptr<std::vector<int, std::allocator<int>>>。我不想复制这些元素,因为它在我的代码中已经很慢的关键部分。如果不是因为分配器不匹配,我将通过简单地执行以下操作来绕过 shared_ptr 要求:

// code that generates std::vector<int, Eigen::aligned_allocator<int>> source
boost::shared_ptr<std::vector<int>> indices(new std::vector<int>);
indices->swap(source);
// use indices as intended

这不能用 MSVC 编译器编译,因为它不能在这两种向量类型之间进行转换。到目前为止我想到的唯一不复制内容的解决方案是:

// code that generates std::vector<int, Eigen::aligned_allocator<int>> source
boost::shared_ptr<std::vector<int>> indices(new std::vector<int>);
indices->swap(reinterpret_cast<std::vector<int>&>(source));
// use indices as intended
indices->swap(reinterpret_cast<std::vector<int>&>(pcout.points));

请注意我需要如何将索引用作常量 shared_ptr。我相信分配器不会在交换操作中发挥作用。整数也不需要任何填充来对齐,因为它们已经是 32 位大小。 std::allocator 版本应该能够从对齐的版本中读取,因为它只能分配 std::allocator 本来可以使用的内存地址。最后,我换回来,因为如果对齐分配器试图删除一个非对齐的保留 space.

,它可能会崩溃

我试过了,它没有崩溃,但这还不足以让我相信它确实是正确的。安全吗?如果不是,如果对编译器做出某些合理的假设,它是否有条件安全?是否有不会显着影响性能的更安全的替代方案?

请不要回复 "profile your code"、"not worth it" 或类似的答案。即使它们在这里适用,理论上存在复制不是可行解决方案的情况,本帖应该解决这个问题。

Similar question 正在谈论以干净的方式复制数据,正如评论中所阐明的那样。

编辑:似乎尽管 Eigen::aligned_allocator 是为 16 位对齐而设计的,但没有向整数添加额外的填充。比较列表中第一个和最后一个元素的地址,可以得出元素数量和 sizeof(int) 所期望的大小。这意味着整数的存储方式应与 std::allocator 版本兼容。我希望我今天晚些时候或未来几天有时间进行更完整的测试。

如果您能够将函数原型更改为另一种向量类型,那么标准库中就有一个全新的命名空间 (namespace pmr),它使用分配器的类型擦除来确保容器之间的兼容性使用不同的分配器。

有关更多信息,请参阅

有了这个改变,你可以简单地做

void foo(std::pmr::vector<int>& vec); 

并传入一个带有任何你想要的分配器的向量类型(只要它也是一个 std::pmr::vector)。

如果您无法更改函数期望的向量类型,我认为您也无法比 copying/moving 逐个元素做得更好。

reinterpret_cast将两个不同的向量实例转换为不同的类型,然后对它们使用方法是非常危险的。