Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Mapping Address Independent Pointer: offset_ptr

When creating shared memory and memory mapped files to communicate two processes the memory segment can be mapped in a different address in each process:

#include<boost/interprocess/shared_memory_object.hpp>

// ...

using boost::interprocess;

//Open a shared memory segment
shared_memory_object shm_obj
   (open_only                    //open or create
   ,"shared_memory"              //name
   ,read_only   //read-only mode
   );

//Map the whole shared memory
mapped_region region
   ( shm                         //Memory-mappable object
   , read_write                  //Access mode
   );

//This address can be different in each process
void *addr = region.get_address();

This makes the creation of complex objects in mapped regions difficult: a C++ class instance placed in a mapped region might have a pointer pointing to another object also placed in the mapped region. Since the pointer stores an absolute address, that address is only valid for the process that placed the object there unless all processes map the mapped region in the same address.

To be able to simulate pointers in mapped regions, users must use offsets (distance between objects) instead of absolute addresses. The offset between two objects in a mapped region is the same for any process that maps the mapped region, even if that region is placed in different base addresses. To facilitate the use of offsets, Boost.Interprocess offers offset_ptr.

offset_ptr wraps all the background operations needed to offer a pointer-like interface. The class interface is inspired in Boost Smart Pointers and this smart pointer stores the offset (distance in bytes) between the pointee's address and it's own this pointer. Imagine a structure in a common 32 bit processor:

struct structure
{
   int               integer1;   //The compiler places this at offset 0 in the structure
   offset_ptr<int>   ptr;        //The compiler places this at offset 4 in the structure
   int               integer2;   //The compiler places this at offset 8 in the structure
};

//...

structure s;

//Assign the address of "integer1" to "ptr".
//"ptr" will store internally "-4":
//    (char*)&s.integer1 - (char*)&s.ptr;
s.ptr = &s.integer1;

//Assign the address of "integer2" to "ptr".
//"ptr" will store internally "4":
//    (char*)&s.integer2 - (char*)&s.ptr;
s.ptr = &s.integer2;

One of the big problems of offset_ptr is the representation of the null pointer. The null pointer can't be safely represented like an offset, since the absolute address 0 is always outside of the mapped region. Due to the fact that the segment can be mapped in a different base address in each process the distance between the address 0 and offset_ptr is different for every process.

Some implementations choose the offset 0 (that is, an offset_ptr pointing to itself) as the null pointer pointer representation but this is not valid for many use cases since many times structures like linked lists or nodes from STL containers point to themselves (the end node in an empty container, for example) and 0 offset value is needed. An alternative is to store, in addition to the offset, a boolean to indicate if the pointer is null. However, this increments the size of the pointer and hurts performance.

In consequence, offset_ptr defines offset 1 as the null pointer, meaning that this class can't point to the byte after its own this pointer:

using namespace boost::interprocess;

offset_ptr<char> ptr;

//Pointing to the next byte of it's own address
//marks the smart pointer as null.
ptr = (char*)&ptr + 1;

//ptr is equal to null
assert(!ptr);

//This is the same as assigning the null value...
ptr = 0;

//ptr is also equal to null
assert(!ptr);

In practice, this limitation is not important, since a user almost never wants to point to this address.

offset_ptr offers all pointer-like operations and random_access_iterator typedefs, so it can be used in STL algorithms requiring random access iterators and detected via traits. For more information about the members and operations of the class, see offset_ptr reference.


PrevUpHomeNext