Como tornar meu uninitialised_allocator seguro?
A partir deessa questão, Eu quero usar umunitialised_allocator
com, digamos,std::vector
para evitar a inicialização padrão dos elementos na construção (ouresize()
dostd::vector
(Veja tambémAqui para um caso de uso). Meu design atual é assim:
// based on a design by Jared Hoberock
template<typename T, typename base_allocator >
struct uninitialised_allocator : base_allocator::template rebind<T>::other
{
// added by Walter Q: IS THIS THE CORRECT CONDITION?
static_assert(std::is_trivially_default_constructible<T>::value,
"value type must be default constructible");
// added by Walter Q: IS THIS THE CORRECT CONDITION?
static_assert(std::is_trivially_destructible<T>::value,
"value type must be default destructible");
using base_t = typename base_allocator::template rebind<T>::other;
template<typename U>
struct rebind
{
typedef uninitialised_allocator<U, base_allocator> other;
};
typename base_t::pointer allocate(typename base_t::size_type n)
{
return base_t::allocate(n);
}
// catch default construction
void construct(T*)
{
// no-op
}
// forward everything else with at least one argument to the base
template<typename Arg1, typename... Args>
void construct(T* p, Arg1 &&arg1, Args&&... args)default_
{
base_t::construct(p, std::forward<Arg1>(arg1), std::forward<Args>(args)...);
}
};
Então umunitialised_vector<>
template poderia ser definido assim:
template<typename T, typename base_allocator = std::allocator<T>>
using uninitialised_vector =
std::vector<T,uninitialised_allocator<T,base_allocator>>;
No entanto, como indicado pelos meus comentários, não tenho 100% de certeza quanto aoquais são as condições apropriadas nostatic_assert()
? (Btw, pode-se considerar SFINAE em vez disso - quaisquer comentários úteis sobre isso são bem-vindos)
Obviamente, é preciso evitar o desastre que resultaria da tentativa de destruição não trivial de um objeto não inicializado. Considerar
unitialised_vector< std::vector<int> > x(10); // dangerous.
Foi sugerido (comentário por Evgeny Panasyuk) que afirmo a construtibilidade trivial, mas isso não parece capturar o cenário de desastre acima. Eu apenas tentei checar o que o clang fala sobrestd::is_trivially_default_constructible<std::vector<int>>
(oustd::is_trivially_destructible<std::vector<int>>
) mas tudo o que eu consegui foi um choque de clang 3.2 ...
Outra opção, mais avançada, seria projetar um alocador que apenas elimina a construção padrão para objetos para os quais isso seria seguro.