{"id":8272,"date":"2023-09-25T07:43:22","date_gmt":"2023-09-25T07:43:22","guid":{"rendered":"https:\/\/www.modernescpp.com\/?p=8272"},"modified":"2023-09-25T19:33:48","modified_gmt":"2023-09-25T19:33:48","slug":"polymorphic-allocators-in-c17","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/polymorphic-allocators-in-c17\/","title":{"rendered":"Polymorphic Allocators in C++17"},"content":{"rendered":"\n<p>This post starts a miniseries about an almost unknown feature in C++17: polymorphic allocators. I often promised that I would write about polymorphic allocators. Today, I fulfill my promise.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large is-resized\"><img decoding=\"async\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/09\/ram-921458_1280-1030x773.jpg\" alt=\"\" class=\"wp-image-8275\" style=\"width:650px\" width=\"650\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/09\/ram-921458_1280-1030x773.jpg 1030w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/09\/ram-921458_1280-300x225.jpg 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/09\/ram-921458_1280-768x576.jpg 768w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/09\/ram-921458_1280-705x529.jpg 705w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/09\/ram-921458_1280.jpg 1280w\" sizes=\"(max-width: 1030px) 100vw, 1030px\" \/><\/figure>\n\n\n\n<p>Since C++98, you can fine-tune memory allocation in general but also for user-defined types or containers of the standard library. For example, the containers of the sequential and associative containers of the STL have a defaulted allocator parameter. For example, here are the containers <code>std::string<\/code>, <code>std::vector<\/code>, and <code>std::unordered_map<\/code>:<\/p>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto; gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\"><span style=\"color: #006699; font-weight: bold\">template<\/span><span style=\"color: #555555\">&lt;<\/span><span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">CharT<\/span>, <span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">Traits<\/span> <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>char_traits<span style=\"color: #555555\">&lt;<\/span>CharT<span style=\"color: #555555\">&gt;<\/span>,\n         <span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">Allocator<\/span> <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>allocator<span style=\"color: #555555\">&lt;<\/span>CharT<span style=\"color: #555555\">&gt;&gt;<\/span> \n<span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">basic_string<\/span>;\n<span style=\"color: #006699; font-weight: bold\">using<\/span> string <span style=\"color: #555555\">=<\/span> basic_string<span style=\"color: #555555\">&lt;<\/span><span style=\"color: #007788; font-weight: bold\">char<\/span><span style=\"color: #555555\">&gt;<\/span>;\n\n<span style=\"color: #006699; font-weight: bold\">template<\/span><span style=\"color: #555555\">&lt;<\/span><span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">T<\/span>, <span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">Allocator<\/span> <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>allocator<span style=\"color: #555555\">&lt;<\/span>T<span style=\"color: #555555\">&gt;&gt;<\/span> \n<span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">vector<\/span>;\n\n<span style=\"color: #006699; font-weight: bold\">template<\/span><span style=\"color: #555555\">&lt;<\/span><span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">Key<\/span>, <span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">T<\/span>, <span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">Hash<\/span> <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>hash<span style=\"color: #555555\">&lt;<\/span>Key<span style=\"color: #555555\">&gt;<\/span>,\n         <span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">KeyEqual<\/span> <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>equal_to<span style=\"color: #555555\">&lt;<\/span>Key<span style=\"color: #555555\">&gt;<\/span>,\n         <span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">Allocator<\/span> <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>allocator<span style=\"color: #555555\">&lt;<\/span>std<span style=\"color: #555555\">::<\/span>pair<span style=\"color: #555555\">&lt;<\/span><span style=\"color: #006699; font-weight: bold\">const<\/span> Key, T<span style=\"color: #555555\">&gt;&gt;&gt;<\/span>\n<span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">unordered_map<\/span>;\n<\/pre><\/div>\n\n\n\n<p>The memory is allocated from the heap by default, but this default is not always appropriate. Often, you want to apply another strategy. Here are a few ideas.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>You want to use the stack instead of the heap for memory allocation.<\/li>\n\n\n\n<li>You want to use your memory allocation strategy and reduce the number of memory allocations.<\/li>\n\n\n\n<li>You want to allocate contiguous memory blocks to benefit from CPU caching.<\/li>\n\n\n\n<li>You want to allocate but don&#8217;t deallocate memory.<\/li>\n\n\n\n<li>You want to reuse a memory pool.<\/li>\n\n\n\n<li>You want to have a thread-safe memory allocation.<\/li>\n\n\n\n<li>You want to use different allocators for different types.<\/li>\n\n\n\n<li>You want to change the allocation strategy for a type if its size increases.<\/li>\n<\/ul>\n\n\n\n<p>With C++98, you could implement and use your memory allocator, but this was pretty challenging and error-prone. I have already written two posts about memory allocators in C++: &#8220;<a href=\"https:\/\/www.modernescpp.com\/index.php\/memory-management-with-std-allocator\/\">Memory Management with <code>std::allocator<\/code><\/a>&#8221; and a guest post from Jonathan M\u00fcller &#8220;<a href=\"https:\/\/www.modernescpp.com\/index.php\/memory-pool-allocators-with-jonathan-mueller\/\">Memory Pool Allocators<\/a>&#8220;. <\/p>\n\n\n\n<p>Thanks to polymorphic allocators in C++17, your job becomes way easier. Before I dive into the details, let me give you an introductory example.<\/p>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto; gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\"><span style=\"color: #0099FF; font-style: italic\">\/\/ polymorphicAllocator.cpp<\/span>\n\n<span style=\"color: #009999\">#include &lt;array&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;cstddef&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;memory_resource&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;vector&gt;<\/span>\n\n<span style=\"color: #007788; font-weight: bold\">int<\/span> <span style=\"color: #CC00FF\">main<\/span>() {\n\n    std<span style=\"color: #555555\">::<\/span>array<span style=\"color: #555555\">&lt;<\/span>std<span style=\"color: #555555\">::<\/span>byte, <span style=\"color: #FF6600\">200<\/span><span style=\"color: #555555\">&gt;<\/span> buf1;                               <span style=\"color: #0099FF; font-style: italic\">\/\/ (1)<\/span>\n    std<span style=\"color: #555555\">::<\/span>pmr<span style=\"color: #555555\">::<\/span>monotonic_buffer_resource pool1{buf1.data(), buf1.size()};\n    std<span style=\"color: #555555\">::<\/span>pmr<span style=\"color: #555555\">::<\/span>vector<span style=\"color: #555555\">&lt;<\/span><span style=\"color: #007788; font-weight: bold\">int<\/span><span style=\"color: #555555\">&gt;<\/span> myVec1{<span style=\"color: #555555\">&amp;<\/span>pool1};                          <span style=\"color: #0099FF; font-style: italic\">\/\/ (3)<\/span>\n    <span style=\"color: #006699; font-weight: bold\">for<\/span> (<span style=\"color: #007788; font-weight: bold\">int<\/span> i <span style=\"color: #555555\">=<\/span> <span style=\"color: #FF6600\">0<\/span>; i <span style=\"color: #555555\">&lt;<\/span> <span style=\"color: #FF6600\">5<\/span>; <span style=\"color: #555555\">++<\/span>i) {\n        myVec1.push_back(i);\n    }\n\n    <span style=\"color: #007788; font-weight: bold\">char<\/span> buf2[<span style=\"color: #FF6600\">200<\/span>] <span style=\"color: #555555\">=<\/span> {};                                           <span style=\"color: #0099FF; font-style: italic\">\/\/ (2)<\/span>\n    std<span style=\"color: #555555\">::<\/span>pmr<span style=\"color: #555555\">::<\/span>monotonic_buffer_resource pool2{std<span style=\"color: #555555\">::<\/span>data(buf2), std<span style=\"color: #555555\">::<\/span>size(buf2)};\n    std<span style=\"color: #555555\">::<\/span>pmr<span style=\"color: #555555\">::<\/span>vector<span style=\"color: #555555\">&lt;<\/span><span style=\"color: #007788; font-weight: bold\">int<\/span><span style=\"color: #555555\">&gt;<\/span> myVec2{<span style=\"color: #555555\">&amp;<\/span>pool2};\n    <span style=\"color: #006699; font-weight: bold\">for<\/span> (<span style=\"color: #007788; font-weight: bold\">int<\/span> i <span style=\"color: #555555\">=<\/span> <span style=\"color: #FF6600\">0<\/span>; i <span style=\"color: #555555\">&lt;<\/span> <span style=\"color: #FF6600\">200<\/span>; <span style=\"color: #555555\">++<\/span>i) {\n        myVec2.push_back(i);\n    }\n\n}\n<\/pre><\/div>\n\n\n\n<p>First, I allocate memory on the stack. I can use a <code>byte<\/code> array (line 1) or a char array (line 2) for that job. Furthermore, I initialize a<code> std:pmr::motonotic_buffer<\/code> with the address and the size of the already stack-allocated memory. The final step is that the<code> std::pmr::vector<\/code> takes this memory resource. <\/p>\n\n\n\n<p>The namespace component pmr stands for a polymorphic memory resource. All components of the polymorphic allocators are in this namespace. The containers of the STL have their pmr pendants. This pmr pendant is  an alias for a<code> std::vector<\/code> using the special allocator. The following two lines are equivalent:<\/p>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto; gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\">std<span style=\"color: #555555\">::<\/span>pmr<span style=\"color: #555555\">::<\/span>vector<span style=\"color: #555555\">&lt;<\/span><span style=\"color: #007788; font-weight: bold\">int<\/span><span style=\"color: #555555\">&gt;<\/span> myVec1{<span style=\"color: #555555\">&amp;<\/span>pool1}; \n\nstd<span style=\"color: #555555\">::<\/span>vector<span style=\"color: #555555\">&lt;<\/span><span style=\"color: #007788; font-weight: bold\">int<\/span>, std<span style=\"color: #555555\">::<\/span>pmr<span style=\"color: #555555\">::<\/span>polymorphic_allocator<span style=\"color: #555555\">&lt;<\/span><span style=\"color: #007788; font-weight: bold\">int<\/span><span style=\"color: #555555\">&gt;&gt;<\/span> myVec1{<span style=\"color: #555555\">&amp;<\/span>pool1};\n<\/pre><\/div>\n\n\n\n<p>When you study the example <code>polymorphicAllocator.cpp<\/code>, you may wonder: How could a vector of 200 <code>int<\/code>&#8216;s myVec2 fit into a <code>char <\/code>array of 200 elements? The answer is simple:<code> std::pmr::new_delete_resource() <\/code>as the so-called upstream allocator kicks in as a<code> <\/code>fallback. C++17 provides a few predefined memory resources.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Predefined Memory Resources<\/h2>\n\n\n\n<p>I will apply the listed predefined memory resources in upcoming posts. Therefore, here is a short overview. All predefined memory resources are derived from the interface class <code>std::pmr::memory_resource<\/code>. The class provides three public member functions <code>allocate<\/code>, <code>deallocate<\/code>, and<code> is_equal.<\/code><\/p>\n\n\n\n<p>Correspondingly, <code>std:pmr::memory_resource<\/code> has three private virtual member functions<code> do_allocate<\/code>, <code>do_deallocate<\/code>, and <code>do_is_equal<\/code>. Typically, a user-defined memory resource overwrites these three virtual member functions, as do the predefined memory resources:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><code>std::pmr::new_delete_resource<\/code><\/h3>\n\n\n\n<p>Returns a pointer to a memory resource, calling the global <code>new <\/code>and <code>delete<\/code>. It is the default memory resource if not otherwise specified.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><code>std::pmr::null_memory_resource<\/code><\/h3>\n\n\n\n<p>Returns a pointer to a &#8220;null&#8221; memory resource. Using this memory resource for allocating causes a <code>std::bad_alloc<\/code> exception. This memory resource ensures you do not arbitrarily allocate memory on the heap.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><code>std::pmr::synchronized_pool_resource<\/code><\/h3>\n\n\n\n<p>A class that creates a memory resource with less fragmentation that is thread-safe. This class acts as a wrapper around the default resource.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><code>std::pmr::unsynchronized_pool_resource<\/code><\/h3>\n\n\n\n<p>A class that creates a memory resource with less fragmentation that is not thread-safe. This class acts as a wrapper around the default resource.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><code>std::pmr::monotonic_buffer_resource<\/code><\/h3>\n\n\n\n<p>A class to create memory resources in a big chunk of memory that is not thread-safe. You can optionally pass it as a buffer. This memory resource is pretty fast and can only grow. It destroys the objects but does not free the memory.<\/p>\n\n\n\n<p>I used in the previous program <code>polymorphicAllocator.cpp<\/code> a <code>std::pmr::monotonic_buffer<\/code> with a <code>byte<\/code>-array (line 1) and a <code>char<\/code>-array (line 2) as a passed buffer. Additionally, the vector <code>myVec2 <\/code>allocated the remaining memory with the default allocator (upstream allocator)<code> std::pmr::new_delete_resource<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What&#8217;s Next? <\/h2>\n\n\n\n<p>Admittedly, his was a technical post. In my next post, I will apply the theory and implement a tracking memory resource. This user-defined memory resource will track all allocations and deallocations of the upstream allocator. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>This post starts a miniseries about an almost unknown feature in C++17: polymorphic allocators. I often promised that I would write about polymorphic allocators. Today, I fulfill my promise. Since C++98, you can fine-tune memory allocation in general but also for user-defined types or containers of the standard library. For example, the containers of the [&hellip;]<\/p>\n","protected":false},"author":21,"featured_media":8275,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[370],"tags":[556,498],"class_list":["post-8272","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c-17","tag-allocator","tag-memory"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/8272","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/comments?post=8272"}],"version-history":[{"count":38,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/8272\/revisions"}],"predecessor-version":[{"id":8373,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/8272\/revisions\/8373"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/8275"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=8272"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=8272"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=8272"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}