EDIT: after clarification from the OP, the original answer seems to be off topic; for reference, it is at the end of this answer.
Actually, the answer is quite simple: you just need to save a pointer to both the storage unit and the first element.
In fact, this does not require a generator with installed states (this is possible even in C ++ 03, although with the user-defined subroutine std::align ). The trick is that the distributor does not need to request enough memory from the system to store user data. He may well ask a little more about accounting.
So here we create a aligned dispenser; to keep it simple, I will focus on distribution / release routines.
template <typename T> class aligned_allocator {
And now the distribution procedure. A lot of memory is busy, this is the heart of the dispenser after all!
template <typename T> auto aligned_allocator<T>::allocate(size_type n) -> pointer { size_type const alignment = std::max(alignof(ptrdiff_t), alignof(T)); size_type const object_size = sizeof(ptrdiff_t) + sizeof(T)*n; size_type const buffer_size = object_size + alignment;
Fortunately, the redistribution procedure is much simpler, you just need to read the offset and apply it.
template <typename T> void aligned_allocator<T>::deallocate(pointer p, size_type) { // find the offset field char const* header = reinterpret_cast<char*>(p) - sizeof(ptrdiff_t); // read its value ptrdiff_t const offset = *reinterpret_cast<ptrdiff_t*>(header); // apply it to find start of block void* const block = reinterpret_cast<char*>(p) - offset; // finally deallocate std::free(block); } // aligned_allocator<T>::deallocate
Other routines do not need to know about the memory layout, so writing them is trivial.
Original answer:
template <typename T> class Block { public: Block(Block const&) = delete; Block& operator=(Block const&) = delete; explicit Block(size_t n); ~Block(); private: void* _storage; T* _begin; T* _end; };
Matthieu M. Jun 29. '13 at 13:53 on 2013-06-29 13:53
source share