My goal is to have a memory pool non-template class that is used to store arrays of objects. The same memory pool object must be reusable for a different array (difference size, different type and/or alignement).
I already posted a series of questions but they might have been too focused on technicals details about a possible implementation, while this implementation might not be the correct one:
- type-punning and strict aliasing rule for array of objects
- type-punning: omitting placement new and destructors
- type-punning with std::aligned_alloc for array of objects
I will, with this question, focus on the "what".
I'd like to have a memory-pool class with this pseudo-code API (and an usage example):
// type-punning reusable buffer for arrays
// holds a non-typed buffer (actually a char*) that can be used to store any
// types, according to user needs
struct Buffer {
// start of storage address
char* p = nullptr;
// adding whatever method and variable required to make it work
// ...
// Creates an adequate storage (if needed) to store an array of N object of
// type T and default-construct them returns a pointer to the first element
// of this array
template <typename T>
T* DefaultAllocate(const size_t N);
// Ends lifetime of the currently stored array of objects, if any, leaving
// the storage reusable for another array of possibly different type and
// size
// Make it non-template if possible
// Make it optional if possible (by calling it automatically in
// DefaultAllocate if needed)
template <typename T>
void Deallocate() {}
// Releasing all ressources (storage and objects)
~Buffer() {}
};
int main() {
constexpr std::size_t N0 = 7;
constexpr std::size_t N1 = 3;
Buffer B;
std::cout << "Test on SomeClass\n";
SomeClass* psc = B.DefaultAllocate<SomeClass>(N0);
psc[0] = somevalue0;
*(psc + 1) = somevalue1;
psc[2] = somevalue2;
std::cout << psc[0] << '\n';
std::cout << psc[1] << '\n';
std::cout << *(psc + 2) << '\n';
std::cout << "Test on SomeOtherClass\n";
// reallocating, possibly using existing storage, for a different type and
// size
SomeOtherClass* posc = B.DefaultAllocate<SomeOtherClass>(N1);
std::cout << posc[0] << '\n';
std::cout << posc[1] << '\n';
std::cout << posc[2] << '\n';
return 0;
}
Editable version in compiler explorer.
How should be implemented this class to avoid UB, memory leaks, to let pointer arithmetic be valid on the typed pointer (the one returned by ``DefaultAllocate```) and have proper alignment?
I'm expecting C++14 answers with technical references and explanations (what ensures the absence of UB, the validity of pointer arithmetic,...).
But I'm also interested in how to do that in more modern versions (especially as there has been some fundamental changes that lead to the need of std::launder in some specific situations).
NB In type-punning with std::aligned_alloc for array of objects, a very interesting technics (using std::function and lambdas has been proposed in order to help data erasing).
Bufferjust be an Allocator, and use/pass it in container such asstd::vector?anyclass, for arrays and with reusable storage.