Initial vector capacity in C ++

What is capacity() for std::vector , which is created using the standard constuctor? I know that size() is zero. Can we state that the default vector does not cause heap memory allocation?

Thus, it is possible to create an array with an arbitrary reserve using one selection, for example std::vector<int> iv; iv.reserve(2345); std::vector<int> iv; iv.reserve(2345); . Let's say that for some reason I don't want to run size() on 2345.

For example, on Linux (g ++ 4.4.5, kernel 2.6.32 amd64)

 #include <iostream> #include <vector> int main() { using namespace std; cout << vector<int>().capacity() << "," << vector<int>(10).capacity() << endl; return 0; } 

printed 0,10 . Is this a rule, or does it depend on the STL provider?

+63
c ++ memory-management vector stl
Sep 04
source share
5 answers

The standard does not specify what the initial capacity container should be, so you rely on implementation. The overall implementation will start bandwidth to zero, but there is no guarantee. On the other hand, there is no way to improve your strategy std::vector<int> iv; iv.reserve(2345); std::vector<int> iv; iv.reserve(2345); so stick with it.

+47
Sep 04
source share

The std :: vector repository implementations vary significantly, but all the ones I came across start at 0.

The following code:

 #include <iostream> #include <vector> int main() { using namespace std; vector<int> normal; cout << normal.capacity() << endl; for (unsigned int loop = 0; loop != 10; ++loop) { normal.push_back(1); cout << normal.capacity() << endl; } std::cin.get(); return 0; } 

Gives the following output:

 0 1 2 4 4 8 8 8 8 16 16 

under GCC 5.1 and:

 0 1 2 3 4 6 6 9 9 9 13 

at MSVC 2013.

+16
Apr 2 '16 at 8:34
source share

As a small addition to other answers, I found that when working under debugging conditions in Visual Studio, the default vector will still be allocated to the heap, even if the capacity starts from scratch.

In particular, if _ITERATOR_DEBUG_LEVEL! = 0, then the vector will allocate some space to help with checking the iterator.

https://docs.microsoft.com/en-gb/cpp/standard-library/iterator-debug-level

I just found this a bit annoying since at that time I was using a custom dispenser and did not expect additional distribution.

+2
Mar 01 '18 at 10:44
source share

As far as I understood the standard (although I really could not name the link), container initialization and memory allocation were intentionally untied for a good reason. For this, you have separate, separate calls for

  • constructor to create the container itself
  • reserve() to preallocate a sufficiently large block of memory to accommodate at least (!) a given number of objects

And that makes a lot of sense. The only right of existence for reserve() is to give you the ability to code, possibly costly redistributions when growing a vector. To be useful, you need to know the number of objects to store, or at least be able to make an educated guess. If this is not given to you, it is better to stay away from reserve() as you simply change the allocation for wasted memory.

So all together:

  • The standard intentionally does not indicate a constructor that allows you to pre-allocate a memory block for a certain number of objects (which would be at least more desirable than allocating a specific concrete implementation, a fixed β€œsomething” under the hood).
  • Allocation should not be implied. So, in order to pre-allocate the block, you need to make a separate call for reserve() and this does not have to be at the same construction site (it may, of course, be later, after you find out about the required size for placement )
  • Thus, if the vector always preinstalled a memory block of a certain implementation size, this would distort the intended operation of reserve() , would it?
  • What would be the advantage of block pre-allocation if the STL, of course, cannot know the intended purpose and expected vector size? It would be pretty pointless, if not counterproductive.
  • Instead, the correct solution is to allocate and implement a specific block using the first push_back() - if it has not already been explicitly allocated before reserve() .
  • In the case of the necessary redistribution, an increase in the block size also depends on the implementation. The implemented vector implementations, which I know, start with an exponential increase in size, but they will overlap the increment speed with a certain maximum to avoid wasting huge amounts of memory or even purging.

All this is achieved by full operation and advantage only if it is not violated by the selection designer. You have reasonable defaults for common scripts that can be overridden with reserve() (and shrink_to_fit() ). Thus, even if the standard does not explicitly state this, I am quite sure that the newly constructed vector does not provide a sufficiently safe bet for all current implementations.

+2
Apr 19 '18 at 8:34
source share

The standard does not define the initial value of capacity, but the STL container automatically grows to accommodate as much data as you insert if you do not exceed the maximum size (use the max_size member function to know). For a vector and a string, growth is handled by realloc whenever more space is required. Suppose you want to create a vector value of 1-1000. Without using a reserve, the code usually leads to a redistribution between 2 and 18 in the following cycle:

 vector<int> v; for ( int i = 1; i <= 1000; i++) v.push_back(i); 

Changing the code to use the reserve can lead to 0 distributions during the cycle:

 vector<int> v; v.reserve(1000); for ( int i = 1; i <= 1000; i++) v.push_back(i); 

Roughly speaking, vector and string powers grow in each range from 1.5 to 2 times.

0
Mar 01 '18 at 11:14
source share



All Articles