Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to store stl objects in shared memory (C++)?

I've the following code pattern:

class A {
    double a, b, c;
    ...
};

class B {
    map<int, A> table; // Can have maximum of MAX_ROWS elements.
    ...
};

class C {
    B entries;
    queue<int> d;
    queue<int> e;
    ...
};

Now I want to store an object of type C in a shared memory, so that different processes can append, update and read it. How can I do this? (Note: I know how to store a simple C array that has a fixed size in shared memory. Also, remember that B.table may have arbitrary entries.

like image 358
shobhu Avatar asked Aug 31 '12 07:08

shobhu


People also ask

Are STL containers allocated on heap?

std::vector always has its buffer allocated on heap. So regardless of where the vector itself is allocated resizing it will only affect the heap.

How are STL containers implemented in C++?

In C++, STL Unordered Associative Containers provide the unsorted versions of the associative container. Internally, unordered associative containers are implemented as hash table data structures.

Are STL containers slow?

Yes, you are correct. Using the vector or string like that is indeed slow. Basically every time you append you're appending to the end of the container, you're potentially asking the container to reallocate a new buffer, copy the data over to the new buffer, and delete the old buffer.


1 Answers

Use boost::interprocess, this library exposes this functionality.

EDIT: Here are some changes you'll need to do:

The example already defines an allocator that will allocate from the shared memory block, you need to pass this to the map and the queue. This means you'll have to change your definitions:

class B
{
  map<int, A, less<int>, MapShmemAllocator> table;

  // Constructor of the map needs the instance of the allocator
  B(MapShmemAllocator& alloc) : table(less<int>(), alloc)
  { }
}

For queue, this is slightly complicated, because of the fact that it's really just an adapter, so you need to pass in the real implementation class as a template parameter:

typedef queue<int, deque<int, QueueShmemAllocator> > QueueType;

Now your class C changes slightly:

class C
{
  B entries;
  QueueType d, e;

  C(MapShmemAllocator& allocM, QueueShmemAllocator& allocQ) : entries(allocM), d(allocQ), e(allocQ)
  { }
}

Now from the segment manager, construct an instance of C with the allocator.

C *pC = segment.construct<C>("CInst")(allocM_inst, allocQ_inst); 

I think that should do the trick. NOTE: You will need to provide two allocators (one for queue and one for map), not sure if you can construct two allocators from the same segment manager, but I don't see why not.

like image 188
Nim Avatar answered Oct 02 '22 05:10

Nim