At [Value-Initialized Objects in C++11 and std::vector constructor, Channel72 asks,
Question: Is my understanding correct here? Does explicit std::vector(size_type count) provide an uninitialized array (similar to malloc) if T is a POD?
The answer is no.
My question is, "Okay then, what does?"
One of the responses, by Nevin, hints at answering my question. To clarify, my question is, Is there a way to use std::vector<double> without it gratuitously filling allocated memory with zeros or whatever?
I am not asking for workarounds, like starting the vector at zero size and using push_back(). That is not always possible, and besides, at this point I want to get it figured out for no other reason than I want to get it figured out.
I cannot get Nevin's suggestion, a custom allocator, to compile. VC++ 2017rc (Dinkum) complains in its usual inscrutable way. Something about std::_Wrap_alloc. Nevin's code is incomplete, and I probably do not know how to complete it. Before I saw his, I wrote my own custom allocator which seems to work, but I am not confident in my understanding enough to swear by it.
For the time I have spent puzzling over this, I could have written a less dogmatic replacement for std::vector, plus several chapters of the Great American Novel.
HOORAY! Richard Critten to the rescue! His comment under the question leads directly to the answer.
The zero-spewing culprit is the default allocator template, namely std::allocator. So we replace it, or modify it with an allocator adapter.
I tidied up the code a little, and expanded the comments. Bill, please feel free to post a more comprehensive answer. But the following does the trick very nicely.
// Allocator adapter
// Given an allocator A, (std::allocator by default), this adapter
// will, when feasible, override A::construct() with a version that
// employs default construction rather than value-initialization.
// "Feasible" means the object (U *ptr) is default-constructable and
// the default constructor cannot throw exceptions.
//
// Thus it thwarts gratuitous initializations to zeros or whatever.
template <typename T, typename A = std::allocator<T>>
class default_init_allocator : public A {
typedef std::allocator_traits<A> a_t;
public:
// http://en.cppreference.com/w/cpp/language/using_declaration
using A::A; // Inherit constructors from A
template <typename U> struct rebind {
using other =
default_init_allocator
< U, typename a_t::template rebind_alloc<U> >;
};
template <typename U>
void construct(U* ptr)
noexcept(std::is_nothrow_default_constructible<U>::value) {
::new(static_cast<void*>(ptr)) U;
}
template <typename U, typename...Args>
void construct(U* ptr, Args&&... args) {
a_t::construct(static_cast<A&>(*this),
ptr, std::forward<Args>(args)...);
}
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With