Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set *both* elements and initial capacity of std::vector

Tags:

c++

c++11

vector

I've read in this post that the initial capacity of a std::vector couldn't be controlled by its constructor. The best way to set it, if you know its size will be constant at runtime, seems then to be:

const int size;
std::vector<T> v;
v.reserve(size);

But, since T is a big class, I'm happy to use the initialization argument of the constructor std::vector<T> v(size, T());. What is then the best way to allocate only the memory I need without having to manually iterate over the elements to initialize them?

std::vector<T> v;
v.reserve(size);
for(T t : v) t = T();    // `has to call T::operator= (that may not even be defined)

or

std::vector<T> v(size, T());  // may allocate more memory than I need..
v.shrink_to_fit();            // ..then deallocate it immediately (pointless)

What would be the closest to my ideal:

std::vector<T> v(size, T(), /*capacity =*/ size);

[EDIT]: It turns out from your answers that what I need more exactly is v to be filled with size instances of T, each build with T's default constructor, and not copied. How can I do since I can't use an initializer list when size isn't known at compile time?


Bonus: By the way, why is there no way choosing the initial capacity of a vector?

like image 288
iago-lito Avatar asked Feb 21 '26 15:02

iago-lito


2 Answers

Bonus first:

Bonus: By the way, why is there no way choosing the initial capacity of a vector?

Because the designers of the class never considered it important enough to include.


I know of no implementation where after:

std::vector<T> v(size, T());

the following assert does not hold:

assert(v.capacity() == size);

It isn't guaranteed by the standard to hold. But it does appear to be the de-facto standard.

One can not however transfer this bit of lore to std::string.


If you want to positively require that capacity() == size() after construction, you could use shrink_to_fit(). That being said, shrink_to_fit() isn't guaranteed by the standard to work, and if it does do anything at all, it will temporarily double your memory requirements. Such use might look like:

std::vector<T> v(size, T());
if (v.capacity() > v.size())
    v.shrink_to_fit(); // If executed and successful, this will allocate a new buffer
if (v.capacity() > v.size())
    // now what?

Use of reserve() is no more effective. After reserve(), capacity() is greater or equal to the argument of reserve if reallocation happens; and equal to the previous value of capacity() otherwise.

like image 128
Howard Hinnant Avatar answered Feb 24 '26 05:02

Howard Hinnant


It's not clear how you want all the elements constructed. Let's say you want the vector to have n elements and capacity desired_capacity, which may be equal to n.

If you want n elements identical, try this:

std::vector<T> v(n, t);  // creates n copies of the value t.
v.reserve(desired_capacity);

If you don't want to specify an initial value, you can omit that:

std::vector<T> v(n);     // creates n copies of T, default constructed.
v.reserve(desired_capacity);

If you have a certain number of elements you want to specify individually, try an initializer list.

std::vector({t1, t2, ..., tn});  // initializer list
v.reserve(desired_capacity);

The list of possibilities goes on; for more, see the vector::vector reference. Using "in-place" construction means you can populate a vector with types that are not copy-constructible.

Another option, to fill a vector with non-copyable types, is to use emplace_back repeatedly:

std::vector<T> v;
v.reserve(n); 
for (int i = 0; i < n; ++i)
{
   v.emplace_back(x, y, z);  // Construct T(x, y, z) in-place
}

One note about your original question: your for loop contains an error:

for(T t : v) t = T();    
// almost certainly want for (T& t : v) ...
// in order to get references to modify vector elements.
like image 40
NicholasM Avatar answered Feb 24 '26 04:02

NicholasM



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!