Following from this question, I want to use an unitialised_allocator
with, say, std::vector
to avoid default initialisation of elements upon construction (or resize()
of the std::vector
(see also here for a use case). My current design looks like this:
// 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)...);
}
};
Then an unitialised_vector<>
template could be defined like this:
template<typename T, typename base_allocator = std::allocator<T>>
using uninitialised_vector =
std::vector<T,uninitialised_allocator<T,base_allocator>>;
However, as indicated by my comments, I'm not 100% certain as to what are the appropriate conditions in the static_assert()
? (Btw, one may consider SFINAE instead -- any useful comments on this are welcome)
Obviously, one has to avoid the disaster that would ensue from the attempted non-trivial destruction of an uninitialised object. Consider
unitialised_vector< std::vector<int> > x(10); // dangerous.
It was suggested (comment by Evgeny Panasyuk) that I assert trivial constructibility, but this does not seem to catch the above disaster scenario. I just tried to check what clang says about std::is_trivially_default_constructible<std::vector<int>>
(or std::is_trivially_destructible<std::vector<int>>
) but all I got was a crash of clang 3.2 ...
Another, more advanced, option would be to design an allocator which only elides the default construction for objects for which this would be safe to do so.
See Question&Answers more detail:os