1

Let's say I typedef a vector to be used in boost shared memory. When creating it, I have to give an allocator from a managed_shared_memory, which makes sense.

If I want to use this same vector type but to allocate it not in shared memory but instead allocating it on the standard process memory space.

Is it possible by giving a different allocator to the object ?

Do I have to change the definition of my vector to be able to accept both implementations ?

Is it impossible to do and therefore I should use a different kind of vector instead ?

Sample code I am trying to fix :

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/allocators/allocator.hpp>

using namespace boost::interprocess;

typedef managed_shared_memory::segment_manager SegmentMgr;
typedef allocator<int, SegmentMgr> IntAlloc;
typedef vector<int, IntAlloc> IntVector;

int main()
{
  shared_memory_object::remove("Boost");
  managed_shared_memory managed_shm{ open_or_create, "Boost", 1024 };
  IntAlloc intAlloc = managed_shm.get_segment_manager();
  IntVector vectorInSharedMemory({}, intAlloc);  // <--- this allocates in shared memory
  IntVector vectorInMyOwnPrivateMemorySpace({}, /* ? */); // <--- is there a trick here ?
  return 0;
}
Norgannon
  • 487
  • 4
  • 16

3 Answers3

2

I want to use this same vector type but to allocate it not in shared memory

Let's stop right there. It is not the same vector anymore. Given that the allocator is a template parameter of vector, different allocators means different types.

It is as simple as saying std::vector<int> and std::vector<double> are not even the same type.

Do I have to change the definition of my vector to be able to accept both implementations ?

Yes you can use alias declarations to specify that IntVector is a vector of int of parametrized allocator.

template<typename Alloc> using IntVector=vector<int, Alloc>; // template definition

//    [...]

IntVector<IntAlloc> sharedMemoryVector;
IntVector<std::allocator<int>> localHeapVector;
Norgannon
  • 487
  • 4
  • 16
UmNyobe
  • 22,539
  • 9
  • 61
  • 90
  • 1
    Just realized, you can have your cake and eat it too, when you replace the managed segment with a [`managed_external_buffer`](https://www.boost.org/doc/libs/1_67_0/doc/html/interprocess/managed_memory_segments.html#interprocess.managed_memory_segments.managed_heap_memory_external_buffer) that you can then put anywhere you please (on the local heap or in a (shared) memory map). That way the type can be identical. – sehe Jul 20 '18 at 09:16
1

Yes. I have given an extended answer about this before:

What you call "private memory" is "the local heap" though. You can also have mapped memory with MAP_PRIVATE, which means something else (see mmap and e.g. Opening managed shared memory and mapped files with Copy On Write or Read Only modes)

sehe
  • 374,641
  • 47
  • 450
  • 633
  • 1
    They show what the other answer describes: adding the allocator as a template argument. (It goes into advanced practices to avoid having to pass allocators on every call.) – sehe Jul 20 '18 at 09:17
1

You need to create an allocator class which can be switched at runtime to use either allocator. E.g. something like this (not a complete example but just to give you the idea):

template < typename T >
class switchable_allocator
{
   boost::interprocess::allocator< T, SegmentMgr >* sharedAllocator;
   std::allocator< T > privateAllocator;

public:
   switchable_allocator(boost::interprocess::allocator< T, SegmentMgr >* sharedAllocator) : sharedAllocator(sharedAllocator) {}

   pointer allocate(size_t n)
   {
     if (sharedAllocator)
     {
       return sharedAllocator->allocate(n);
     }
     return privateAllocator.allocate(n);
   }
};
Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
  • That's one approach. Note that making allocators runtime polymorphic might not be appropriate for performance reasons. – sehe Jul 20 '18 at 09:45