...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
As mentioned, container developers might need to change their implementation to make them compatible with Boost.Interprocess, because implementation usually ignore allocators with smart pointers. Hopefully several Boost containers are compatible with Interprocess.
Boost.Unordered containers are compatible
with Interprocess, so programmers can store hash containers in shared memory
and memory mapped files. Here is a small example storing unordered_map
in shared memory:
#include <boost/interprocess/managed_shared_memory.hpp> #include <boost/interprocess/allocators/allocator.hpp> #include <boost/unordered_map.hpp> //boost::unordered_map #include <functional> //std::equal_to #include <boost/container_hash/hash.hpp> //boost::hash int main () { using namespace boost::interprocess; //Remove shared memory on construction and destruction struct shm_remove { shm_remove() { shared_memory_object::remove("MyName"); } ~shm_remove(){ shared_memory_object::remove("MyName"); } } remover; //Create shared memory managed_shared_memory segment(create_only, "MyName", 65536); //Note that unordered_map<Key, MappedType>'s value_type is std::pair<const Key, MappedType>, //so the allocator must allocate that pair. typedef int KeyType; typedef float MappedType; typedef std::pair<const int, float> ValueType; //Typedef the allocator typedef allocator<ValueType, managed_shared_memory::segment_manager> ShmemAllocator; //Alias an unordered_map of ints that uses the previous STL-like allocator. typedef boost::unordered_map < KeyType , MappedType , boost::hash<KeyType> ,std::equal_to<KeyType> , ShmemAllocator> MyHashMap; //Construct a shared memory hash map. //Note that the first parameter is the initial bucket count and //after that, the hash function, the equality function and the allocator MyHashMap *myhashmap = segment.construct<MyHashMap>("MyHashMap") //object name ( 3u, boost::hash<int>(), std::equal_to<int>() // , segment.get_allocator<ValueType>()); //allocator instance //Insert data in the hash map for(std::size_t i = 0; i < 100u; ++i){ myhashmap->insert(ValueType((int)i, (float)i)); } return 0; }
The widely used Boost.MultiIndex library is compatible with Boost.Interprocess so we can construct pretty good databases in shared memory. Constructing databases in shared memory is a bit tougher than in normal memory, usually because those databases contain strings and those strings need to be placed in shared memory. Shared memory strings require an allocator in their constructors so this usually makes object insertion a bit more complicated.
Here is an example that shows how to put a multi index container in shared memory:
#include <boost/interprocess/managed_shared_memory.hpp> #include <boost/interprocess/allocators/allocator.hpp> #include <boost/container/string.hpp> #include <boost/multi_index_container.hpp> #include <boost/multi_index/member.hpp> #include <boost/multi_index/ordered_index.hpp> using namespace boost::interprocess; namespace bmi = boost::multi_index; typedef managed_shared_memory::allocator<char>::type char_allocator; typedef boost::container::basic_string<char, std::char_traits<char>, char_allocator>shm_string; //Data to insert in shared memory struct employee { int id; int age; shm_string name; employee( int id_ , int age_ , const char *name_ , const char_allocator &a) : id(id_), age(age_), name(name_, a) {} }; //Tags struct id{}; struct age{}; struct name{}; // Define a multi_index_container of employees with following indices: // - a unique index sorted by employee::int, // - a non-unique index sorted by employee::name, // - a non-unique index sorted by employee::age. typedef bmi::multi_index_container< employee, bmi::indexed_by< bmi::ordered_unique <bmi::tag<id>, bmi::member<employee,int,&employee::id> >, bmi::ordered_non_unique< bmi::tag<name>, bmi::member<employee,shm_string,&employee::name> >, bmi::ordered_non_unique <bmi::tag<age>, bmi::member<employee,int,&employee::age> > >, managed_shared_memory::allocator<employee>::type > employee_set; int main () { //Remove shared memory on construction and destruction struct shm_remove { shm_remove() { shared_memory_object::remove("MyName"); } ~shm_remove(){ shared_memory_object::remove("MyName"); } } remover; //Create shared memory managed_shared_memory segment(create_only,"MyName", 65536); //Construct the multi_index in shared memory employee_set *es = segment.construct<employee_set> ("My MultiIndex Container") //Container's name in shared memory ( employee_set::ctor_args_list() , segment.get_allocator<employee>()); //Ctor parameters //Now insert elements char_allocator ca(segment.get_allocator<char>()); es->insert(employee(0,31, "Joe", ca)); es->insert(employee(1,27, "Robert", ca)); es->insert(employee(2,40, "John", ca)); return 0; }
Programmers can place Boost.CircularBuffer
containers in shared memory provided they disable debugging facilities with
defines BOOST_CB_DISABLE_DEBUG
or the more general NDEBUG
.
The reason is that those debugging facilities are only compatible with raw
pointers.