In this example, we will create a far more complicated allocator, called a pool allocator. The goal of the pool allocator is to quickly allocate memory for a fixed-size type while simultaneously (and more importantly) reducing internal fragmentation of memory (that is, the amount of memory that is wasted by each allocation, even if the allocation size is not a multiple of two or some other optimized allocation size).
Memory-pool allocators are so useful that some implementations of C++ already contain pool allocators. In addition, C++17 technically has support for a pool allocator in something called a polymorphic allocator (which is not covered in this book, as no major implementations of C++17 have support for polymorphic allocators at the time of writing), and most operating systems leverage pool allocators within...