Vector: Initialization or Reserve

Vector: initialization or reserve?

Both variants have different semantics, i.e. you are comparing apples and oranges.

The first gives you a vector of n default-initialized values, the second variant reserves the memory, but does not initialize them.

Choose what better fits your needs, i.e. what is "better" in a certain situation.

How do I reserve memory for a std::vector at construction time?

Your question is based on a false premise, namely that a default-constructed std::vector<T> will perform a [zero-length] allocation.

There is literally no reason for it to do so. A fresh vector should have capacity zero (though this is required by sanity, not by the standard).

As such, your goal is already inherently satisfied.

To be blunt, the standard library is not quite that stupid.

Initialize vector of vectors with reserved vector

  1. Not invalid, but it doesn't do what you want. As far as I can tell, there is no undefined behavior here.
  2. There may be one unnecessary copy if the optimizer performs badly.

That being said, you're not doing what you set out to do at all. If you check the capacity() of v's elements, you'll see that they're not set to 10. That's because vector's copy constructor is not defined to copy the container verbatim - it copies its elements.

To do what you wanted you need to call reserve() after those vectors have been constructed:

std::vector<std::vector<T>> v(5);
for(auto& vec : v) {
vec.reserve(10);
}

It has the added benefit of being less code and more readable.

When should we use reserve() of vector?

A vector has a capacity (as returned by capacity() and a size (as returned by size(). The first states how many elements a vector can hold, the second how many he does currently hold.

resize changes the size, reserve only changes the capacity.

See also the resize and reserve documentation.

As for the use cases:
Let's say you know beforehand how many elements you want to put into your vector, but you don't want to initialize them - that's the use case for reserve. Let's say your vector was empty before; then, directly after reserve(), before doing any insert or push_back, you can, of course, not directly access as many elements as you reserved space for - that would trigger the mentioned error (subscript out of range) - since the elements you are trying to access are not yet initialized; the size is still 0. So the vector is still empty; but if you choose the reserved capacity in such a way that it's higher or equal to the maximum size your vector will get, you are avoiding expensive reallocations; and at the same time you will also avoid the (in some cases expensive) initialization of each vector element that resize would do.

With resize, on the other hand, you say: Make the vector hold as many elements as I gave as an argument; initialize those whose indices are exceeding the old size, or remove the ones exceeding the given new size.

Note that reserve will never affect the elements currently in the vector (except their storage location if reallocation is needed - but not their values or their number)! Meaning that if the size of a vector is currently greater than what you pass to a call to the reserve function on that same vector, reserve will just do nothing.

See also the answer to this question: Choice between vector::resize() and vector::reserve()

Does vector know to reserve first when initializing by a pair of iterators?

Does my bucket_ do the reserve first when initializing from a pair of iterators?

Yes, it does in effect.

Standard draft:

Complexity: Makes only N calls to the copy constructor of T (where N is the distance between first and last) and no reallocations if iterators first and last are of forward, bidirectional, or random access categories. It makes order N calls to the copy constructor of T and order log(N) reallocations if they are just input iterators.

(Pointers are random access iterators)

What is better: reserve vector capacity, preallocate to size or push back in loop?

Better performance will be reached when avoiding dynamic reallocation, so try to have the vector memory be big enough to receive all elements.

Your first solution will be more efficient because if nSize is bigger than default vector capacity, the second one will need a reallocation to be able to store all elements.

As commented by Melkon, reserve is even better:

void myfnc_1(void *a_src, uint32_t a_segment) {
size_t nSize = GetSize();
std::vector<std::string> values;
values.reserve( nSize );
char* v = a_src;

for (size_t i = 0; i < nSize; ++i) {
values.push_back( std::string( v, a_segment ) );
v += a_segment;
}
}

efficient way to initialize a vector with zero after constructor

I think this method couldn't be efficient.

Well, you can just use the constructor

 std::vector<int> var(100000000,0);

or the resize() function

 var.resize(100000000,0);

I'd suspect these are implemented as efficient as can be, while doing yourself using push_back() may have some unwanted side effects.

Vector of vectors, reserve

Since your inner dimension is constant, I think you want

std::vector< std::array<int, 5> > vecs;
vecs.reserve(N);

This will give you preallocated contiguous storage, which is optimal for performance.

reserve() - data() trick on empty vector - is it correct?

No, you cannot use it.

The standard (current draft, equivalent wording in C++11) says in [vector.data]:

constexpr T* data() noexcept;

constexpr const T* data() const noexcept;

Returns: A pointer such that [data(), data() + size()) is a valid range.
For a non-empty vector, data() == addressof(front()).

You don't have any guarantee that you can access through the pointer beyond the vector's size. In particular, for an empty vector, the last sentence doesn't apply and so you cannot even be sure that you are getting a valid pointer to the underlying array.

There is currently no way to use std::vector with default-initialized elements.


As mentioned in the comments, you can use std::unique_ptr instead (requires #inclue<memory>):

auto data = std::unique_ptr<int[]>{new int[n]};

which will give you a std::unique_ptr<int[]> smart pointer to a dynamically sized array of int's, which will be destroyed automatically when the lifetime of data ends and that can transfer it's ownership via move operations.

It can be dereferenced and indexed directly with the usual pointer syntax, but does not allow direct pointer arithmetic. A raw pointer can be obtained from it via data.get().

It does not offer you the std::vector interface, though. In particular it does not provide access to its allocation size and cannot be copied.


Note: I made a mistake in a previous version of this answer. I used std::make_unique<int[]> without realizing that it actually also performs value-initialization (initialize to zero for ints). In C++20 there will be std::make_unique_default_init<int[]> which will default-initialize (and therefore leave ints with indeterminate value).



Related Topics



Leave a reply



Submit