I need a custom Allocator to create share_pointer objects ultimately using a pool of dedicated memory. For some classes, however, I will need to further specialize the Allocators. These specialized Allocators, however, are never called.
The example defines a templeted custom allocator, and specializes the allocator for class Special.
#include <memory>
#include "stdio.h"
#include "stdint.h"
#include "string.h"
void* memAllocate(const size_t amount) {
void* result = new char[amount];
printf("memAllocate: %p\n", result);
return result;
}
void memFree(void *pointer) {
printf("memFree: %p\n", pointer);
delete pointer;
}
typedef struct General {
char buffer[100];
} General;
typedef struct Special {
char buffer[100];
} Special;
template <class T>
class Allocator
{
public:
using value_type = T;
using pointer = value_type*;
Allocator() noexcept {}
template <class U> Allocator(Allocator<U> const&) noexcept {}
value_type* allocate(std::size_t n)
{
value_type* result = static_cast<value_type*>(memAllocate(n*sizeof(value_type)));
printf("Allocator<generic>::allocate: %p\n", result);
return result;
}
void deallocate(value_type* p, std::size_t n) noexcept
{
printf("Allocator<generic>::deallocate: %p\n", p);
memFree(p);
}
};
template <>
class Allocator<Special>
{
public:
using value_type = Special;
using pointer = value_type*;
Allocator() noexcept {}
template <class U> Allocator(Special const&) noexcept {}
Special* allocate(std::size_t n)
{
Special* result = static_cast<Special*>(memAllocate(n*sizeof(Special)));
printf("Allocator<Special>::allocate: %p\n", result);
return result;
}
void deallocate(Special* p, std::size_t) noexcept
{
printf("Allocator<Special>::deallocate: %p\n", p);
memFree(p);
}
};
template <class T, class U>
bool operator==(Allocator<T> const&, Allocator<U> const&) noexcept
{
return true;
}
template <class T, class U>
bool operator!=(Allocator<T> const& x, Allocator<U> const& y) noexcept
{
return !(x == y);
}
int main(int argc, char **argv) {
{
Allocator<General> general;
std::shared_ptr<General> sptr = std::allocate_shared<General>(general);
sptr.reset();
}
{
Allocator<Special> special;
std::shared_ptr<Special> sptr = std::allocate_shared<Special>(special);
sptr.reset();
}
return 0;
}
Using g++ version 12.2.0 and c++17: The output for the example code shows that while my custom allocator is called, even for the Special case the generic version is used.
// general
memAllocate: 0x55ea3b904eb0
Allocator<generic>::allocate: 0x55ea3b904eb0
Allocator<generic>::deallocate: 0x55ea3b904eb0
memFree: 0x55ea3b904eb0
// special
memAllocate: 0x55ea3b904eb0
Allocator<generic>::allocate: 0x55ea3b904eb0
Allocator<generic>::deallocate: 0x55ea3b904eb0
memFree: 0x55ea3b904eb0
What am I doing wrong? My theory is that the allocator is not called for the plain General and Special classes but rather some classes templeted therefrom.
I expect that in the general case, Allocator is used, while for class Special Allocator is used.
What type is used by std::allocate_shared to allocate memory? seems to relate to my problem though I don't understand the answers.
std::allocate_shared<T>generally doesn't allocate memory forT, but rather for some internal data structure that contains an instance ofTas well as a control block. The allocator you pass is rebound to the type of that structure.destroy(T* p)method (if not provided,std::destroy_at(p)is called, which in turn callsp->~T()). This one should be called on the "right" allocator type. This is another way, besides custom deleter, to customize destruction.