object_pool.h.xml 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. <chapter>
  2. <title><tt>__vic/object_pool.h</tt></title>
  3. <chapter>
  4. <title><tt>object_pool</tt></title>
  5. <code-block lang="C++"><![CDATA[
  6. template<class T>
  7. class object_pool : private non_copyable
  8. {
  9. public:
  10. using object_type = T;
  11. using value_type = object_type; // standard synonym
  12. using iterator = ]]><nt>&lt;implementation-defined></nt><![CDATA[;
  13. using const_iterator = ]]><nt>&lt;implementation-defined></nt><![CDATA[;
  14. class overflow; // : public std::exception
  15. object_pool();
  16. explicit object_pool(size_t max_size);
  17. ~object_pool();
  18. // BEGIN C++11 only
  19. object_pool(object_pool &&o) noexcept;
  20. object_pool &operator=(object_pool &&o) noexcept;
  21. template<class... Args> void emplace(Args &&... args)
  22. // END C++11 only
  23. // size in objects
  24. size_t size() const;
  25. size_t capacity() const;
  26. bool empty();
  27. void recreate(size_t new_max_size, bool size_exact = false);
  28. void *alloc(); // returns pointer to memory for object allocation
  29. void push(); // adds last allocated object to the pool
  30. void pop();
  31. void clear();
  32. void swap(object_pool &o) noexcept;
  33. // element access
  34. object_type &operator[](size_t i);
  35. iterator begin();
  36. iterator end();
  37. object_type &front();
  38. object_type &back();
  39. const object_type &operator[](size_t i) const;
  40. const_iterator begin() const;
  41. const_iterator end() const;
  42. const_iterator cbegin() const;
  43. const_iterator cend() const;
  44. const object_type &front() const;
  45. const object_type &back() const;
  46. };
  47. template<class T>
  48. void swap(object_pool<T> &o1, object_pool<T> &o2) noexcept;
  49. ]]></code-block>
  50. <p>The standard containers in C++98 don't allow to store non-copiable elements.
  51. Even in C++11 elements of containers like <tt>std::vector</tt> have to be at
  52. least movable. This class solves the problem. It is an array for non-copyable
  53. objects.</p>
  54. <p>Without <tt>emplace()</tt> it is impossible to create arbitrary new object
  55. right in the container's memory. C++98 lacks forwarding references so it is
  56. near impossible to pass arbitrary parameters to the element's constructor.
  57. <tt>object_pool</tt> solves this problem using the following mechanism.
  58. The new element is created using several phases:</p>
  59. <list style="numbered">
  60. <item>Requesting memory for the new element in the container -
  61. <tt>alloc()</tt>,</item>
  62. <item>Creation of the object using placement new -
  63. <tt>new(ptr) type(...)</tt>,</item>
  64. <item>Fixation of the newly created object in the container -
  65. <tt>push()</tt>.</item>
  66. </list>
  67. <p>See the example at the end of the article.</p>
  68. <p>Maximum pool capacity is specified on creation of the container. Later it
  69. can be changed but all the elements has to be destroyed before. In other words,
  70. the pool can be recreated.</p>
  71. <p>When available, <tt>emplace()</tt> must be used for elements creation. If
  72. not, the unsafe interface described above must be used with care. It is very
  73. ugly and error-prone but solves the task. After the element is created in the
  74. pool, you operate with it almost as easy as with any other copyable object in
  75. the standard container. Anyway, it is more efficient and convenient to use in
  76. general than alternative approaches like creating the objects on the free
  77. store and placing only pointers to the container, even if we have
  78. <tt>std::unique_ptr</tt> to manage lifetime of the objects.</p>
  79. <section><title>Class members</title>
  80. <synopsis>
  81. <prototype>typename object_type</prototype>
  82. <prototype>typename value_type</prototype>
  83. <p>Type of the elements.</p>
  84. </synopsis>
  85. <synopsis>
  86. <prototype>typename iterator</prototype>
  87. <prototype>typename const_iterator</prototype>
  88. <p>Iterators.</p>
  89. </synopsis>
  90. <synopsis>
  91. <prototype>class overflow</prototype>
  92. <p>Exception, thrown on attempts to add new element to the full container.
  93. </p>
  94. </synopsis>
  95. <synopsis>
  96. <prototype>object_pool()</prototype>
  97. <p>Create the object without memory allocation.</p>
  98. <postcondition><tt>capacity() == 0</tt></postcondition>
  99. </synopsis>
  100. <synopsis>
  101. <prototype>explicit object_pool(size_t max_size)</prototype>
  102. <p>Allocates memory for <tt>max_size</tt> elements.</p>
  103. <postcondition><tt>capacity() == max_size</tt></postcondition>
  104. </synopsis>
  105. <synopsis>
  106. <prototype>~object_pool()</prototype>
  107. <p>Calls <tt>clear()</tt>.</p>
  108. </synopsis>
  109. <synopsis>
  110. <prototype>object_pool(object_pool &amp;&amp;o) noexcept <sign>C++11</sign></prototype>
  111. <prototype>object_pool &amp;operator=(object_pool &amp;&amp;o) noexcept <sign>C++11</sign></prototype>
  112. <p>Move operations for C++11 mode.</p>
  113. </synopsis>
  114. <synopsis>
  115. <prototype>size_t size() const</prototype>
  116. <prototype>size_t capacity() const</prototype>
  117. <p>Current size and capacity of the container.</p>
  118. </synopsis>
  119. <synopsis>
  120. <prototype>bool empty()</prototype>
  121. <p>Returns <tt>size() == 0</tt>.</p>
  122. </synopsis>
  123. <synopsis>
  124. <prototype>void recreate(size_t new_max_size, bool size_exact = false)</prototype>
  125. <p>Recreates the container. At first calls <tt>clear()</tt>, then reallocates
  126. memory buffer if <tt>new_max_size > capacity()</tt> or <tt>size_exact</tt> is
  127. <tt>true</tt> and <tt>new_max_size != capacity()</tt>.</p>
  128. <postcondition><tt>capacity() >= new_max_size &amp;&amp; empty() == true</tt>
  129. (if <tt>size_exact == true</tt> then <tt>capacity() == new_max_size &amp;&amp;
  130. empty() == true</tt>)</postcondition>
  131. </synopsis>
  132. <synopsis>
  133. <prototype>void *alloc()</prototype>
  134. <p>Returns the raw memory block where new instance of <tt>object_type</tt>
  135. can be allocated. <tt>overflow</tt> is thrown if the container is full.</p>
  136. <note>Use <tt>emplace()</tt> in C++11 mode.</note>
  137. </synopsis>
  138. <synopsis>
  139. <prototype>void push()</prototype>
  140. <p>This call right after <tt>alloc()</tt> adds the just created object to the
  141. pool.</p>
  142. </synopsis>
  143. <synopsis>
  144. <prototype>template&lt;class... Args> void emplace(Args &amp;&amp;... args) <sign>C++11</sign></prototype>
  145. <p>Constructs new object and adds it to the container (<tt>alloc()</tt> +
  146. <tt>new</tt> + <tt>push()</tt> with a single call).</p>
  147. </synopsis>
  148. <synopsis>
  149. <prototype>void pop()</prototype>
  150. <p>Remove the last element from the container if exists.</p>
  151. </synopsis>
  152. <synopsis>
  153. <prototype>void clear()</prototype>
  154. <p>Destroys the elements in the reverse order they were created.</p>
  155. <postcondition><tt>size() == 0</tt> (<tt>empty() == true</tt>)</postcondition>
  156. </synopsis>
  157. <synopsis>
  158. <prototype>void swap(object_pool &amp;o)</prototype>
  159. <prototype><![CDATA[template<class T> void swap(object_pool<T> &o1, object_pool<T> &o2) noexcept]]></prototype>
  160. <p>Swaps the value with <tt>o</tt>.</p>
  161. </synopsis>
  162. <synopsis>
  163. <prototype>object_type &amp;operator[](size_t i)</prototype>
  164. <prototype>const object_type &amp;operator[](size_t i) const</prototype>
  165. <p>Access to the elements by index.</p>
  166. </synopsis>
  167. <synopsis>
  168. <prototype>object_type &amp;front()</prototype>
  169. <prototype>const object_type &amp;front() const</prototype>
  170. <prototype>object_type &amp;back()</prototype>
  171. <prototype>const object_type &amp;back() const</prototype>
  172. <p>Access to the first and the last elements.</p>
  173. <precondition>!empty()</precondition>
  174. </synopsis>
  175. <synopsis>
  176. <prototype>iterator begin()</prototype>
  177. <prototype>const_iterator begin() const</prototype>
  178. <prototype>const_iterator cbegin() const</prototype>
  179. <prototype>iterator end()</prototype>
  180. <prototype>const_iterator end() const</prototype>
  181. <prototype>const_iterator cend() const</prototype>
  182. <p>Access to the elements via iterators.</p>
  183. </synopsis>
  184. </section>
  185. <section><title>Example</title>
  186. <code-block lang="C++"><![CDATA[
  187. // Creating the pool for 2 objects of class C
  188. __vic::object_pool<C> pool(2);
  189. // Creating new object in C++98 mode:
  190. new(pool.alloc()) C(...); // Request memory and construct the object
  191. pool.push(); // Fixate successfully created object in the container
  192. // Creating new object in C++11 mode:
  193. pool.emplace(...);
  194. ]]></code-block>
  195. </section>
  196. </chapter>
  197. </chapter>