100

There is a thread in the comments section in this post about using std::vector::reserve() vs. std::vector::resize().

Here is the original code:

void MyClass::my_method()
{
    my_member.reserve(n_dim);
    for(int k = 0 ; k < n_dim ; k++ )
         my_member[k] = k ;
}

I believe that to write elements in the vector, the correct thing to do is to call std::vector::resize(), not std::vector::reserve().

In fact, the following test code "crashes" in debug builds in VS2010 SP1:

#include <vector>

using namespace std;

int main()
{
    vector<int> v;
    v.reserve(10);
    v[5] = 2;

    return 0;
}

Am I right, or am I wrong? And is VS2010 SP1 right, or is it wrong?

Community
  • 1
  • 1
Mr.C64
  • 41,637
  • 14
  • 86
  • 162
  • I agree with you, but no doubt Luchian will be along soon enough to explain. – john Oct 23 '12 at 11:22
  • 12
    The explanation might be as simple as "I was wrong" :D – Luchian Grigore Oct 23 '12 at 11:22
  • @LuchianGrigore: That's fine. Everyone can be wrong :) – Mr.C64 Oct 23 '12 at 11:23
  • 7
    I flagged this as "too localized", since @LuchianGrigore is rarely wrong – default Oct 23 '12 at 11:27
  • 1
    @Default read "rarely wrong" as "fast in correcting his mistakes" :) – Luchian Grigore Oct 23 '12 at 11:27
  • @LuchianGrigore no matter what, this question is based on a statement that no longer exists. So as it stands, this question is invalid – default Oct 23 '12 at 11:29
  • 1
    The code in the original post was updated to correctly use `resize()`, and the doubt was cleared. To moderators: feel free to delete this question if it's "too localized", or keep it if you think that it might help someone else in the future. – Mr.C64 Oct 23 '12 at 12:45
  • Related, see [C++ Made Easier: How Vectors Grow](http://www.drdobbs.com/c-made-easier-how-vectors-grow/184401375) from Dr. Dobb's journal. – jww Dec 22 '16 at 05:22
  • Possible duplicate of [Choice between vector::resize() and vector::reserve()](https://stackoverflow.com/questions/7397768/choice-between-vectorresize-and-vectorreserve) – phuclv Jan 04 '18 at 10:21
  • 1
    this question actually clear my doubt when I am migrating my project from vc6 to vs2013.. thanks :)) – pengMiao Jul 03 '19 at 08:14
  • Answered here by **Jan Hudec** : [https://stackoverflow.com/questions/7397768/choice-between-vectorresize-and-vectorreserve](https://stackoverflow.com/questions/7397768/choice-between-vectorresize-and-vectorreserve) – lucasg Oct 23 '12 at 11:26

4 Answers4

141

There are two different methods for a reason:

std::vector::reserve will allocate the memory but will not resize your vector, which will have a logical size the same as it was before.

std::vector::resize will actually modify the size of your vector and will fill any space with objects in their default state. If they are ints, they will all be zero.

After reserve, in your case, you will need a lot of push_backs to write to element 5. If you don't wish to do that then in your case you should use resize.

One thing about reserve: if you then add elements with push_back, until you reach the capacity you have reserved, any existing references, iterators or pointers to data in your vector will remain valid. So if I reserve 1000 and my size is 5, the &vec[4] will remain the same until the vector has 1000 elements. After that, I can call push_back() and it will work, but the stored pointer of &vec[4] earlier may no longer be valid.

CashCow
  • 30,981
  • 5
  • 61
  • 92
  • 1
    so, for empty vector, i.e. vec, after reserve vec[1] will end with segment fault. – hailinzeng Jun 02 '15 at 15:58
  • 3
    vec[1] would be undefined behaviour. – CashCow Jun 02 '15 at 15:59
  • Will `std::vector::reserve` prevent the occasional copying of the full array on `push_back`? – Post Self Apr 20 '17 at 20:25
  • Is this just for C++11 or a specific std implementation? It looks like the code with reserve and access with [] works fine? https://godbolt.org/z/MhgFdZ – Steve Bronder Mar 23 '20 at 03:15
  • 1
    @Steve_Corrin Undefined behaviour is undefined. It can seem to work. It's still invalid code. Indexing at elements that don't exist within the `< size()` of the container is not allowed. They do not exist there, by the definition of the language. If your compiler decides not to launch the nukes and insteads just pokes/peeks RAM in the way you want it to, that's just good luck. Or bad luck, I guess; ideally we could catch all invalid things all programmers would do, but _good luck_ ever getting there! – underscore_d Jun 05 '20 at 09:52
16

It depends on what you want to do. reserve does not add any elements to the vector; it only changes the capacity(), which guarantees that adding elements will not reallocate (and e.g. invalidate iterators). resize adds elements immediately. If you want to add elements later (insert(), push_back()), use reserve. If you want to access elements later (using [] or at()), use resize. So youre MyClass::my_method can be either:

void MyClass::my_method()
{
    my_member.clear();
    my_member.reserve( n_dim );
    for ( int k = 0; k < n_dim; ++ k ) {
        my_member.push_back( k );
    }
}

or

void MyClass::my_method()
{
    my_member.resize( n_dim );
    for ( int k = 0; k < n_dim; ++ k ) {
        my_member[k] = k;
    }
}

Which one you chose is a question of taste, but the code you quote is clearly incorrect.

Oliver Hallam
  • 4,242
  • 1
  • 24
  • 30
James Kanze
  • 150,581
  • 18
  • 184
  • 329
4

There probably should be a discussion about when both methods are called with a number that's LESS than the current size of the vector.

Calling reserve() with a number smaller than the capacity will not affect the size or the capacity.

Calling resize() with a number smaller than current size the container will be reduced to that size effectively destroying the excess elements.

To sum up resize() will free up memory whereas reserve() will not.

Dula
  • 1,404
  • 1
  • 14
  • 29
  • Resize _never_ frees memory. When the size is getting smaller destructors will be called, but the memory is kept (capacity doesn't change). – John Gordon Oct 27 '16 at 15:26
1

resize actually changes the amount of elements in the vector, new items are default constructed if the resize causes the vector to grow.

vector<int> v;
v.resize(10);
auto size = v.size();

in this case size is 10.

reserve on the other hand only requests that the internal buffer be grown to the specified size but does not change the "size" of the array, only its buffer size is changed.

vector<int> v;
v.reserve(10);
auto size = v.size();

in this case size is still 0.

So to answer your question, yes you are right, even if you reserve enough space you are still accessing uninitialized memory with the index operator. With an int thats not so bad but in the case of a vector of classes you would be accessing objects which have not been constructed.

Bounds checking of compilers set to debug mode can obviously be confused by this behavior which may be why you are experiencing the crash.

odinthenerd
  • 5,422
  • 1
  • 32
  • 61