https://www.youtube.com/watch?v=LIb3L4vKZ7U
std::allocator is to allocation what std::vector is to vexation (or: designing allocators that don't not-work)
I don't see that point because this is not a technical argument, is it?
> It's up to the allocator's user to call one of the several available varieties of placement new on the block of memory allocated.
This would have been a point if that's the control you don't have with the allocator interface. But you do.
I imagine that you're not suggesting invoking placement-new oneself all over the place whenever one allocates the backing storage?
> This would have been a point if that's the control you don't have with the allocator interface. But you do.
Well, std::allocator::construct() has been removed in C++20. You still have std::allocator_traits::construct but it just calls std::construct_at().
> you're not suggesting invoking placement-new oneself all over the place whenever one allocates the backing storage
Well, that's what all the standard containers do (vector, list, map, etc). Or you can use std::construct_at() instead but that effectively is a variant of the placement new. Of course, you'd better use std::make_unique()/make_shared() (which normally still devolves to placement new IIRC) instead of manipulating raw pointers and invoking constructors manually.
You and I must have a different definition of "easily "
template<typename T>
struct Foo {
using value_type = T;
Foo() = default;
template<typename U>
constexpr Foo(const Foo <U>&) noexcept {}
T* allocate(std::size_t n) {
if (n > std::numeric_limits<std::size_t>::max() / sizeof(T))
throw std::bad_array_new_length();
auto p = static_cast<T*>(std::malloc(n * sizeof(T)));
if (!p) throw std::bad_alloc();
return p;
}
void deallocate(T* p, std::size_t n) noexcept {
std::free(p);
}
};
And then you go and use it as std::vector<int, Foo<int>> v;
So the complexity is not really in writing the "C++ allocator" but in writing a sufficiently complex memory management logic that will actually make your application/algorithm run faster. And that only you can know given that you're familiar with the memory allocation patterns in your code. C++ allocator is only an interface that allows you to capture that logic and makes it feasible to apply through the code.There's also a lack of traits that can describe what's required of a specialized allocator. For example, std::map only needs to allocate 1 object at a time in practice while std::vector needs to allocate a contiguous count of objects.