Jak uczynić mojego niezainicjowanego alokatora bezpiecznym?
Zto pytanie, Chcę użyćunitialised_allocator
z, powiedzmy,std::vector
aby uniknąć domyślnej inicjalizacji elementów podczas budowy (lubresize()
zstd::vector
(Zobacz teżtutaj dla przypadku użycia). Mój obecny projekt wygląda tak:
// 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)...);
}
};
Potemunitialised_vector<>
szablon można zdefiniować w ten sposób:
template<typename T, typename base_allocator = std::allocator<T>>
using uninitialised_vector =
std::vector<T,uninitialised_allocator<T,base_allocator>>;
Jednak, jak wskazują moje komentarze, nie jestem w 100% pewnyjakie są odpowiednie warunki wstatic_assert()
? (Btw, zamiast tego można rozważyć SFINAE - wszelkie przydatne komentarze na ten temat są mile widziane)
Oczywiście należy unikać katastrofy, która wynikałaby z próby nietrywialnego zniszczenia niezainicjowanego obiektu. Rozważać
unitialised_vector< std::vector<int> > x(10); // dangerous.
Zasugerowano (komentarz Evgeny Panasyuk), że stwierdzam trywialną konstruktywność, ale wydaje się, że nie złapie powyższego scenariusza katastrofy. Próbowałem tylko sprawdzić, o czym mówi clangstd::is_trivially_default_constructible<std::vector<int>>
(lubstd::is_trivially_destructible<std::vector<int>>
) ale wszystko, co dostałem, to katastrofa klang 3.2 ...
Inną, bardziej zaawansowaną opcją byłoby zaprojektowanie alokatora, który będzie tylko domyślną konstrukcją dla obiektów, dla których byłoby to bezpieczne.