问题
Why isn't there an array template specialization for std::allocator<T[]> in c++14?
When playing around trying to specialize std::allocator<T[]> myself I hit a dead-end when implementing the construct() and destroy() method. Is this the reason? Why then have construct() and destroy() part of std::allocator<>?
template <T>
class allocator <T[]> {
// ...most is similar for std::allocator<>...
template <class U, class... Args>
void construct( U *p, Args&&.. args)
{
// what to write for array construction?
// Could be std::initializer_list<T> or uniform initalizer list.
// Want to pass on to constructor somehow.
// ::new ((void *)p) [] U(std::forward<Args>(args)...);
}
template <class U>
void destroy( U* p )
{
// no-op.
}
};
Thanks for any hints!
回答1:
Warning: None of what follows makes sense. Don't do this at home. Don't mix arrays and dynamic allocation. The following serves merely as a mental exercise in spelling out very long template names.
The standard allocator does indeed not provide for array construction, but you can easily build your own allocator that does. Note that we're free to provide construct()
/destroy()
mechanisms as we please:
#include <memory>
#include <type_traits>
template <typename T>
struct array_allocator : std::allocator<T>
{
template <typename C, typename ...Args>
typename std::enable_if<std::is_array<C>::value>::type construct(C * p, Args &&... args)
{
::new (static_cast<void *>(p)) C { std::forward<Args>(args)... };
}
template <typename C, typename ...Args>
typename std::enable_if<!std::is_array<C>::value>::type construct(C * p, Args &&... args)
{
::new (static_cast<void *>(p)) C(std::forward<Args>(args)...);
}
template <typename C, typename ...Args>
typename std::enable_if<std::is_array<C>::value>::type destroy(C * p)
{
using U = typename std::remove_extent<C>::type;
using UAT = typename std::allocator_traits<array_allocator>::template rebind_traits<U>;
typename std::allocator_traits<array_allocator>::template rebind_alloc<U> ra(*this);
for (std::size_t i = 0, e = std::extent<C>::value; i != e; ++i)
{
UAT::destroy(ra, std::addressof((*p)[e - i - 1]));
}
}
template <typename C, typename ...Args>
typename std::enable_if<!std::is_array<C>::value>::type destroy(C * p)
{
p->~C();
}
};
Here is a usage example, allocating and constructing arrays of 13 int
.:
using T = int[13];
using TA = array_allocator<T>;
using TAT = std::allocator_traits<TA>;
#include <iostream>
int main()
{
TA a;
T * p = TAT::allocate(a, 2); // allocates space for two T's
TAT::construct(a, p, 1, 2, 3);
TAT::construct(a, p + 1, 4, 5, 6);
for (T * q = p; q != p + 2; ++q)
for (int * r = *q; r != *q + 13; ++r)
std::cout << *r << "\n";
TAT::destroy(a, p + 1);
TAT::destroy(a, p);
TAT::deallocate(a, p, 2);
}
As linked in the comments, though, beware that it's impossible to prove that the inherited allocate
function returns the correct amount of memory.
来源:https://stackoverflow.com/questions/24542647/allocator-specialized-for-array-types-in-c14