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?
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.
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.
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