Following from this question, I want to use an unitialised_allocator
with, say, std::vector
to avoid default initialisation of elements upon constr
Fwiw, I think the design can be simplified, assuming a C++11 conforming container:
template
class no_init_allocator
{
public:
typedef T value_type;
no_init_allocator() noexcept {}
template
no_init_allocator(const no_init_allocator&) noexcept {}
T* allocate(std::size_t n)
{return static_cast(::operator new(n * sizeof(T)));}
void deallocate(T* p, std::size_t) noexcept
{::operator delete(static_cast(p));}
template
void construct(U*) noexcept
{
static_assert(std::is_trivially_default_constructible::value,
"This allocator can only be used with trivally default constructible types");
}
template
void construct(U* up, A0&& a0, Args&&... args) noexcept
{
::new(up) U(std::forward(a0), std::forward(args)...);
}
};
I see little advantage to deriving from another allocator.
Now you can let allocator_traits
handle rebind
.
Template the construct
members on U
. This helps if you want to use this allocator with some container that needs to allocate something other than a T
(e.g. std::list
).
Move the static_assert
test into the single construct
member where it is important.
You can still create a using
:
template
using uninitialised_vector = std::vector>;
And this still fails to compile:
unitialised_vector< std::vector > x(10);
test.cpp:447:17: error: static_assert failed "This allocator can only be used with trivally default constructible types"
static_assert(std::is_trivially_default_constructible::value,
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I think the test for is_trivially_destructible
is overkill, unless you also optimize destroy
to do nothing. But I see no motivation in doing that since I believe it should get optimized anyway whenever appropriate. Without such a restriction you can:
class A
{
int data_;
public:
A() = default;
A(int d) : data_(d) {}
};
int main()
{
uninitialised_vector v(10);
}
And it just works. But if you make ~A()
non trivial:
~A() {std::cout << "~A(" << data_ << ")\n";}
Then, at least on my system, you get an error on construction:
test.cpp:447:17: error: static_assert failed "This allocator can only be used with trivally default constructible types"
static_assert(std::is_trivially_default_constructible::value,
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I.e. A
is no longer trivially constructible if it has a non-trivial destructor.
However even with the non-trivial destructor you can still:
uninitialised_vector v;
v.push_back(A());
This works, only because I didn't overreach with requiring a trivial destructor. And when executing this I get ~A()
to run as expected:
~A(0)
~A(0)