You didn't build the std::string
, i.e. call it's constructor. The constructor is responsible for initializing the object data. Imagine string
is implemented like this:
struct string {
char* data;
size_t length;
// ...
};
You put this struct in valid memory with your cast, no problem there, but the value of the fields data
and length
is not initialized, so data
points to a random address and length
is garbage, thus when you use the string you get a crash. You must explicitly call the constructor, something like currentSessionIP->string();
before using it, but that's impossible in C++
. Instead you must use the placement new syntax, which combines the cast and the call to the constructor like this:
void * mem = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
currentSessionIP = new (mem) string;
This syntax is shorter and safer since you're sure the constructor is called. But you're still not done, because the string
struct will be in shared memory, but that's just the "header" : the data
has no reason to point inside your shared memory block.
By default std::string
uses std::allocator
which uses standard memory allocation, on your program heap. The solution is to use a custom allocator (template argument to std::basic_string
) to ensure data
always points in the shared memory.Your allocator will be called by the string object at initialization and when you resize the string.
Have a look at this tutorial or at boost interprocess, meanwhile a very crude and incomplete implementation below, just to dive an idea:
// a very simple shared memory allocator
struct shared_alloc {
typedef char value_type;
typedef char* pointer;
//... see http://en.cppreference.com/w/cpp/memory/allocator
pointer cur; // points to a free memory location
shared_alloc() {
cur = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
// todo: lifecycle (free memory block sometime)
}
pointer allocate(size_t n) {
pointer p = cur;
cur += n; // todo bound checking
return p;
}
void deallocate(pointer p, size_t n) {
// todo: do something smart
}
};
// an allocator object
shared_alloc alloc;
// a string with a custom allocator
typedef std::basic_string<char, std::char_traits<char>, shared_alloc> shared_string;
// allocate shared mem for the string object (the header)
void * header_mem = alloc.allocate(sizeof(shared_string));
// create a string object at this location, and use our allocator for the data
shared_string * currentSessionIP =
new( header_mem ) shared_string(alloc);