15

I can't find anything that gives a definitive answer. I was just curious if a std::vector reallocate its internal array only when it absolutely must or will it reallocate ahead of time in anticipation (so to speak).

For example:

std::vector<int> myVector;
for (int i = 0; i < 1000; ++i) myVector.push_back(i);

cout << myVector.size() << '\n'      // Gives 1000 as expected
     << myVector.capacity() << endl; // Gives 1024 which makes sense

If I continue to add elements, is there ever any chance that one of the next 24 items I add will change the capacity or will it only reallocate once I put in a 25th item?

Note:

I did run a test using gcc 4.4.3 under Linux, but and it seems like the reallocation is done "on-demand", but I was curious if I was just lucky or if there is something somewhere stating that this is expected behavior.

Anthony
  • 9,451
  • 9
  • 45
  • 72
  • 1
    Your title is a bit misleading, since "resize" means "change size"; the answer to that is any time you insert or remove an element. What you mean is: when does it change capacity? And you are indeed guaranteed: not until it absolutely needs to. (You can call `reserve()`, for example, and know exactly when the capacity will need to be changed.) – GManNickG Mar 23 '11 at 18:51
  • Changed the title to be more clear. I realized the poor word choice myself a couple minutes ago. Thanks for pointing it out. – Anthony Mar 23 '11 at 18:55

8 Answers8

18

From C++ standard 23.2.4.2:

size_type capacity() const;

Returns: The total number of elements that the vector can hold without requiring reallocation.

Also from Standard

Notes: Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence. It is guaranteed that no reallocation takes place during insertions that happen after a call to reserve() until the time when an insertion would make the size of the vector greater than the size specified in the most recent call to reserve().

So yes, you can be sure.

Edit: As @Bo Persson mentioned there is a catch. Standard doesn't say anything if we never call reserve() . However in practice it works well, because no implementation will care to remember if you called reserve, or not. I believe that this is bug. And as @Martin mentioned in his answer in C++0x draft it is corrected.

UmmaGumma
  • 5,633
  • 1
  • 31
  • 45
  • 3
    There is a catch here. If you never called reserve(), what happens? ;-) – Bo Persson Mar 23 '11 at 19:00
  • 2
    It doesn't actually, this is a known glitch in the standard. It says that **after** reserve() there will be no reallocations until exceeding the capacity. In practice it works well, because no implementation will care to remember if you called reserve, or not. – Bo Persson Mar 23 '11 at 19:23
9

From the standard: n3092: Draft C++0x

23.3.6.2 vector capacity [vector capacity]

void reserve(size_type n);
2 Effects: A directive that informs a vector of a planned change in size, so that it can manage the storage allocation accordingly. After reserve(), capacity() is greater or equal to the argument of reserve if reallocation happens; and equal to the previous value of capacity() otherwise. Reallocation happens at this point if and only if the current capacity is less than the argument of reserve(). If an exception is thrown other than by the move constructor of a non-CopyConstructible type, there are no effects.

23.3.6.4 vector modifiers [vector.modifiers]
Remarks: Causes reallocation if the new size is greater than the old capacity. If no reallocation happens, all the iterators and references before the insertion point remain valid. If an exception is thrown other than by the copy constructor, move constructor, assignment operator, or move assignment operator of T or by any InputIterator operation there are no effects. If an exception is thrown by the move constructor of a non-CopyConstructible T, the effects are unspecified.

Community
  • 1
  • 1
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • I believe this is from C++0x standard draft and not from current standard. – UmmaGumma Mar 23 '11 at 19:15
  • @Ashot: Added note at top to confirm. – Martin York Mar 23 '11 at 19:17
  • For the posters quoting Cplusplus.com. You can get [Payed Copy](http://stackoverflow.com/questions/81656/where-do-i-find-the-current-c-or-c-standard-documents/83763#83763) of the standard. Or a [Free Draft](http://stackoverflow.com/questions/81656/where-do-i-find-the-current-c-or-c-standard-documents/4653479#4653479) version. Now I like cplusplus.com as a quick lookup but I don't want to use it as a reference to validate an argument. – Martin York Mar 23 '11 at 19:27
7

If you look at the documentation for push_back on cplusplus.com it states:

This effectively increases the vector size by one, which causes a reallocation of the internal allocated storage if the vector size was equal to the vector capacity before the call. Reallocations invalidate all previously obtained iterators, references and pointers.

So I very much doubt the size would change before that but you could always test it. At least on my platform the size changes as stated above:

size vs capacity
1020 vs 1024
1021 vs 1024
1022 vs 1024
1023 vs 1024
1024 vs 1024
1025 vs 2048
GWW
  • 43,129
  • 11
  • 115
  • 108
  • +1 for being faster with nearly the same intent (I should maybe pay attention to that little orange bar at the top...) – Xeo Mar 23 '11 at 18:50
  • Ran that test myself, made edits to the question for a little bit of more clarification (and to use the word reallocate instead of resize). – Anthony Mar 23 '11 at 18:51
  • Running a test can never give a "definitive answer", unless one is only interested in a particular version of a particular compiler. You need to refer to the standard. cplusplus.com is *not* the standard. – Mark Ransom Mar 23 '11 at 18:53
  • 1
    @Mark: but it is like wikipedia for C++, `Pretty Darn Accurate` (TM) – rubenvb Mar 23 '11 at 18:56
  • @Mark: I did check the standard and it essentially contains the same quote regarding vector insertion. – GWW Mar 23 '11 at 18:58
3

std::vector would reallocate itself with the increased capacity on demand -- i.e. when current capacity is exceeded (when size() == capacity()).

How much capacity would be added, depend on the implementation: usually new_capacity = old_capacity * factor, where factor is somewhere from 1.5 to 2 (with theoretical ideal equals to Golden section). This is done so that pushing back new elements to the vector would have amortized constant time.

Alexander Poluektov
  • 7,844
  • 1
  • 28
  • 32
2

From cplusplus.com:

But vectors, also have a capacity, which determines the amount of storage space they have allocated, and which can be either equal or greater than the actual size. The extra amount of storage allocated is not used, but is reserved for the vector to be used in the case it grows. This way, the vector does not have to reallocate storage on each occasion it grows, but only when this extra space is exhausted and a new element is inserted (which should only happen in logarithmic frequence in relation with its size).

Xeo
  • 129,499
  • 52
  • 291
  • 397
0

The standard guarantees which calls do not invalidate iterators. Technically, a std::vector could comply with the standard by only doing resizes that don't require copying the data to a new location, i.e., that don't invalidate iterators. I doubt anybody does, though.

So, resizes happen on calls to reserve() or resize() or any other call that is documented as invalidating iterators.

Max Lybbert
  • 19,717
  • 4
  • 46
  • 69
0

http://www.sgi.com/tech/stl/Vector.html states

Memory will be reallocated automatically if more than capacity() - size() elements are inserted into the vector. Reallocation does not change size(), nor does it change the values of any elements of the vector. It does, however, increase capacity(), and it invalidates [5] any iterators that point into the vector.

Winston Ewert
  • 44,070
  • 10
  • 68
  • 83
0

I found these notes helpful:

http://www.sgi.com/tech/stl/Vector.html#2

http://www.sgi.com/tech/stl/FAQ.html (Why does a vector expand its storage by a factor of two when it performs a reallocation?)

However, this is the SGI STL, couldn't find g++ documentation.

Rumpel
  • 27
  • 4