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

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

本文关键字:分配器 std 期望 函数 vector 自定义      更新时间:2023-10-16

我正在使用外部库(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 无论如何都可以使用的地址。最后,我换回去,因为如果对齐的分配器尝试删除未对齐的保留空间,它可能会崩溃。

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

请不要回复"分析您的代码","不值得"或类似的答案。即使它们在这里适用,理论上也存在复制不是一个可行的解决方案的情况,这个线程应该解决这个问题。

类似的问题是谈论以干净的方式复制数据,如评论中所述。

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

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

有关更多信息,请参阅polymorphic_allocator:何时以及为什么要使用它?

通过这种更改,您可以简单地进行

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

并传入具有您想要的任何分配器的向量类型(只要它也是您想要的std::pmr::vector(。

如果您无法更改函数期望的向量类型,我认为您不能比逐个复制/移动元素做得更好。

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

相关文章: