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.
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_cast
ing two different vector instances to different types and then using methods on them is very dangerous.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With