diff --git a/doc/interprocess.qbk b/doc/interprocess.qbk index 49c7021..aeb803c 100644 --- a/doc/interprocess.qbk +++ b/doc/interprocess.qbk @@ -5225,6 +5225,13 @@ and the mapped type is a class that stores several containers: [import ../example/doc_complex_map.cpp] [doc_complex_map] +This example can be simplified if the user designs a type compatible with the +uses-allocator construction. Simplifies code and allows more efficient +operations like the use of transparent functions for lookups and insertions: + +[import ../example/doc_complex_map_uses_allocator.cpp] +[doc_complex_map_uses_allocator] + [endsect] [endsect] diff --git a/example/doc_complex_map.cpp b/example/doc_complex_map.cpp index db191b6..da8172b 100644 --- a/example/doc_complex_map.cpp +++ b/example/doc_complex_map.cpp @@ -20,75 +20,66 @@ //-> using namespace boost::interprocess; +namespace bc = boost::container; //Typedefs of allocators and containers -typedef managed_shared_memory::segment_manager segment_manager_t; -typedef allocator void_allocator; -typedef allocator int_allocator; -typedef boost::container::vector int_vector; -typedef allocator int_vector_allocator; -typedef boost::container::vector int_vector_vector; -typedef allocator char_allocator; -typedef boost::container::basic_string, char_allocator> char_string; +typedef managed_shared_memory::segment_manager seg_mngr_t; +typedef allocator void_alloc_t; +typedef bc::vector > int_vec_t; +typedef bc::vector > int_vec_vec_t; +typedef bc::basic_string + , allocator > string_t; class complex_data { - int id_; - char_string char_string_; - int_vector_vector int_vector_vector_; + string_t string_; + int_vec_vec_t int_vec_vec_; public: - //Since void_allocator is convertible to any other allocator, we can simplify - //the initialization taking just one allocator for all inner containers. - complex_data(int id, const char *name, const void_allocator &void_alloc) - : id_(id), char_string_(name, void_alloc), int_vector_vector_(void_alloc) + + complex_data(const char *name, const void_alloc_t &valloc) //void_alloc_t is convertible to allocator + : string_(name, valloc), int_vec_vec_(valloc) {} - //Other members... //<- - int get_id() { return id_; }; - char_string get_char_string() { return char_string_; }; - int_vector_vector get_int_vector_vector() { return int_vector_vector_; }; + string_t get_char_string() { return string_; }; + int_vec_vec_t get_int_vector_vector() { return int_vec_vec_; }; //-> }; //Definition of the map holding a string as key and complex_data as mapped type -typedef std::pair map_value_type; -typedef std::pair movable_to_map_value_type; -typedef allocator map_value_type_allocator; -typedef boost::container::map< char_string, complex_data - , std::less, map_value_type_allocator> complex_map_type; +typedef std::pair map_value_type; +typedef allocator map_value_type_allocator; +typedef bc::map< string_t, complex_data, std::less + , map_value_type_allocator> complex_map_type; int main () { + //<- //Remove shared memory on construction and destruction struct shm_remove { shm_remove() { shared_memory_object::remove(test::get_process_id_name()); } ~shm_remove(){ shared_memory_object::remove(test::get_process_id_name()); } } remover; - //<- + (void)remover; //-> + managed_shared_memory segment(create_only,test::get_process_id_name(), 65536); //Create shared memory - //Create shared memory - managed_shared_memory segment(create_only,test::get_process_id_name(), 65536); + //An allocator convertible to any allocator type + void_alloc_t alloc_inst (segment.get_segment_manager()); - //An allocator convertible to any allocator type - void_allocator alloc_inst (segment.get_segment_manager()); - - //Construct the shared memory map and fill it + //Construct the map calling map(key_compare, allocator_type), the allocator argument is explicit complex_map_type *mymap = segment.construct - //(object name), (first ctor parameter, second ctor parameter) - ("MyMap")(std::less(), alloc_inst); + ("MyMap")(std::less(), alloc_inst); + + //Both key(string) and value(complex_data) need an allocator in their constructors + string_t key_object(alloc_inst); + complex_data mapped_object("default_name", alloc_inst); + map_value_type value(key_object, mapped_object); + //Modify values and insert them in the map + mymap->insert(value); - for(int i = 0; i < 100; ++i){ - //Both key(string) and value(complex_data) need an allocator in their constructors - char_string key_object(alloc_inst); - complex_data mapped_object(i, "default_name", alloc_inst); - map_value_type value(key_object, mapped_object); - //Modify values and insert them in the map - mymap->insert(value); - } return 0; } //] diff --git a/example/doc_complex_map_uses_allocator.cpp b/example/doc_complex_map_uses_allocator.cpp index 8b09f26..2bdd1e3 100644 --- a/example/doc_complex_map_uses_allocator.cpp +++ b/example/doc_complex_map_uses_allocator.cpp @@ -20,95 +20,63 @@ //-> using namespace boost::interprocess; +namespace bc = boost::container; //Typedefs of allocators and containers -typedef managed_shared_memory::segment_manager segment_manager_t; -typedef allocator void_allocator; -typedef allocator int_allocator; -typedef boost::container::vector int_vector; -typedef allocator int_vector_allocator; -typedef boost::container::vector int_vector_vector; -typedef allocator char_allocator; -typedef boost::container::basic_string, char_allocator> char_string; +typedef managed_shared_memory::segment_manager seg_mngr_t; +typedef allocator void_alloc_t; +typedef bc::vector > int_vec_t; +typedef bc::vector > int_vec_vec_t; +typedef bc::basic_string + , allocator > string_t; class complex_data { - int id_; - char_string char_string_; - int_vector_vector int_vector_vector_; + string_t string_; + int_vec_vec_t int_vec_vec_; public: - //Mark this class as uses-allocator construction-ready (see Boost.Container's docs) - //Boost.Interprocess machinery will pass the allocator argument automatically if - //constructors takes the allocator_type as the last argument of constructors - typedef void_allocator allocator_type; + typedef void_alloc_t allocator_type; //Activates the uses-allocator protocol - //Since void_allocator is convertible to any other allocator, we can simplify - //the initialization taking just one allocator for all inner containers. - complex_data(int id, const char *name, const void_allocator &void_alloc) - : id_(id), char_string_(name, void_alloc), int_vector_vector_(void_alloc) + complex_data(const char *name, const void_alloc_t &valloc) //void_alloc_t is convertible to allocator + : string_(name, valloc), int_vec_vec_(valloc) {} - //Other members... //<- - int get_id() { return id_; }; - char_string get_char_string() { return char_string_; }; - int_vector_vector get_int_vector_vector() { return int_vector_vector_; }; + string_t get_char_string() { return string_; }; + int_vec_vec_t get_int_vector_vector() { return int_vec_vec_; }; //-> }; -//A transparent comparison functor -//Allows creating associative container `value_type`s from comparable -//types (e.g. shared memory string types from "const char *" arguments) -struct less_transparent +struct lessthan //A transparent comparison functor { typedef void is_transparent; - - template - bool operator() (const T &t, const U &u) const - { return t < u; } + template bool operator() (const T &t, const U &u) const { return t < u; } }; //Definition of the map holding a string as key and complex_data as mapped type -typedef std::pair map_value_type; -typedef std::pair movable_to_map_value_type; -typedef allocator map_value_type_allocator; -typedef boost::container::map< char_string, complex_data - , less_transparent, map_value_type_allocator> complex_map_type; +typedef std::pair map_value_type; +typedef allocator map_value_type_allocator; +typedef boost::container::map< string_t, complex_data, lessthan + , map_value_type_allocator> complex_map_type; int main () { + //<- //Remove shared memory on construction and destruction struct shm_remove { shm_remove() { shared_memory_object::remove(test::get_process_id_name()); } ~shm_remove(){ shared_memory_object::remove(test::get_process_id_name()); } } remover; - //<- (void)remover; //-> + managed_shared_memory segment(create_only, test::get_process_id_name(), 65536); //Create shared memory - //Create shared memory - managed_shared_memory segment(create_only, test::get_process_id_name(), 65536); - - //Construct the shared memory map (associated with name "MyMap") and fill it using "extended uses allocator construction". - //In this case "construct" tries to automatically pass the allocator argument to the constructed - //type in addition to user-supplied arguments. "Uses-allocator construction" from the C++ standard - // - //In this case, no user arguments are provided, but the segment manager machinery has - //detected that boost::container::map supports the user-allocator-construction protocol - //so it automatically adds the allocator parameter and calls map::map(allocator_type) constructor. + //Construct the map calling map(key_compare, allocator_type), the allocator argument is implicit complex_map_type *mymap = segment.construct("MyMap")(); - //This transparent insertion function plus uses-allocator construction so that - //the programmer does not need to explicitly pass allocator instances. The container, - //through boost::container::allocator::construct function, automatically adds the needed allocator - //arguments without forcing the user to supply them, calling the following constructors: - // - //key_type --> basic_string(const char *, allocator_type) - //mapped_type --> complex_data(int, const char *, allocator_type) - // - //The programmer only needs to specify the non-allocator arguments - mymap->try_emplace("key_str", 3, "default_name"); + //Take advantage of transparent insertion, string_t and complex_data are constructed with implicit allocators + mymap->try_emplace("key_str", "default_name"); return 0; }