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

一世执手 提交于 2020-07-08 09:40:34

问题


I am working with an external library (pcl) so I need a solution that does not change the existing function prototypes.

One function that I am using generates an std::vector<int, Eigen::aligned_allocator<int>>. The function that I want to call next expects a const boost::shared_ptr<std::vector<int, std::allocator<int>>>. I do not want to copy the elements because it is in an already slow critical part of my code. If not for the allocator mismatch, I would get around the shared_ptr requirement by simply doing:

// 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

This does not compile with the MSVC compiler because it cannot convert between these two vector types. The only solution I have thought of so far that does not copy the contents is:

// 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));

Note how I need to use indices as as a const shared_ptr. I believe that the allocator will not play a role in the swap operation. The ints should also not need any padding to be aligned as they are already of size 32-bit. The std::allocator version should be able to read from the aligned version because it can only allocate in memory addresses that the std::allocator could have used anyway. Finally, I swap back because the aligned allocator might crash if it tries to delete a non-aligned reserved space.

I tried it and it didn't crash but that is not enought to convince me that it is actually correct. Is it safe? If not, is it conditionally safe if certain reasonable assumptions are made concerning the compiler? Is there a safer alternative that does not noticeably impact performance?

Please do not reply with "profile your code", "not worth it" or similar answers. Even if they are applicable here, there is theoretically a scenario where copying is not a viable solution, and this thread should address that.

Similar question is talking about copying the data in a clean way as was clarified in the comments.

EDIT: it seems that despite Eigen::aligned_allocator being designed for 16-bit alignment, no extra padding is added to the ints. Comparing the address of the first and last element on the list gives the size one would expect from the number of elements and the sizeof(int). This means that the ints are stored in a way that should be compatible with the std::allocator version. I hope I'll have time later today or in the coming days to make a more complete test.


回答1:


If you have the ability to change the function prototype to another vector type, then there is an entirely new namespace (namespace pmr) in the standard library that uses type erasure for allocators to ensure compatibility between containers that use different allocators.

For more see polymorphic_allocator: when and why should I use it?

With that change you can simply do

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

and pass in a vector type with any allocator you want (as long as it is also a std::pmr::vector) you want.

If you are not able to change the type of vector the function expects than I don't think you can do much better than copying/moving the elements one by one.

reinterpret_casting two different vector instances to different types and then using methods on them is very dangerous.



来源:https://stackoverflow.com/questions/44953076/how-to-pass-an-stdvector-with-custom-allocator-to-a-function-that-expects-one

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