4

can someone please explain to me in detail why the following code for vectorY will do the assignment but the size of VecY is zero? Also, the begin and end iterators are stuck at the first node. It seems that reserve only works with push back and that you need to construct the vector with the size if you want the iterators for the vectors and the size to work as expected. I am assuming that push_back is doing some type of allocation that the straight assignment is not in this case? I am looking for details explaining this so I can make sure I understand what is happening with a reserve and push_back versus constructing with a size element and then doing assignment as in VecX example.

#include <iostream>
#include <vector>

    int main ( int argc, char *argv[])
    {
      std::vector<int> vecX(2);
      vecX[0] = 1;
      vecX[1] = 2;
      std::cout << " VecX0 Item: " << vecX[0] << std::endl;
      std::cout << " VecX1 Item: " << vecX[1] << std::endl;
      std::cout << " VectorX Size: " << vecX.size() << std::endl;

      std::vector<int> vecY;
      vecY.reserve(2);
      vecY[0] = 1;
      vecY[1] = 2;
      std::cout << " VecY0 Item: " << vecY[0] << std::endl;
      std::cout << " VecY1 Item: " << vecY[1] << std::endl;
      std::cout << " VectorY Size: " << vecY.size() << std::endl;
    }

Output

 VecX0 Item: 1
 VecX1 Item: 2
 VectorX Size: 2
 VecY0 Item: 1
 VecY1 Item: 2
 VectorY Size: 0
bjackfly
  • 3,236
  • 2
  • 25
  • 38
  • Have you read any manuals about what `vector` is and how it works? This is all very standard and well-documented material. – Kerrek SB Jul 18 '13 at 14:52
  • possible duplicate of [vector::push\_back vs vector::operator\[\]](http://stackoverflow.com/questions/11007054/vectorpush-back-vs-vectoroperator) – Mgetz Jul 18 '13 at 14:52

2 Answers2

7
std::vector<int> vecY;
      vecY.reserve(2);
      vecY[0] = 1;
      vecY[1] = 2;

This code is wrong and evokes Undefined Behavior1. When you reserve a vector, you set the capacity, not the size.

You need to either push_back, or construct the vector as you did in example 1.


"Undefined Behavior" : This invokes Undefined Behavior because of the out-of-range call to operator[] If you call vector::operator[n] where n > vec.size(), the behavior is Undefined.

John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • 7
    It's really really **really** bad code, but with a POD type, is it actually undefined behavior? The Standard says that the lifetime of a POD begins when storage is allocated (`reserve` does this) and you start using it. – Ben Voigt Jul 18 '13 at 14:56
  • @BenVoigt: I thought that it was. I will confirm. – John Dibling Jul 18 '13 at 15:00
  • Hmm. `a[n]` is defined to be equivalent to `*(a.begin()+n)`, and nothing seems to guarantee `vecY.begin()+1` is valid in this case. But I can't find anything that specifically says it's invalid, either. – aschepler Jul 18 '13 at 15:36
  • @Ben: vecY.reserve() allocates storage for the vector. It doesn't allocate the storage for the POD object. The storage and POD object are associated when push_back() is called, i.e. when "new (&vecY[0])int(1)" and new (&vecY[1]) int(2)" would have been called. – ROTOGG Jul 18 '13 at 15:44
  • @Leon: `[basic.life]` 3.8 Object lifetime makes no distinction between "storage for the vector" vs "storage for the POD object". It says that the POD object begins to exist when "storage with the proper alignment and size for type `T` is obtained" -- which requirement preallocated capacity of a `vector` certainly meets. POD objects have trivial initialization, so calling the constructor ala placement new is explicitly not required. – Ben Voigt Jul 18 '13 at 15:47
  • @BenVoigt: Busy at work. I hanven't had a chance to confirm (or not) the UB-ness of this code, but I can tell you the basis of my conclusions. I thought that a requirement of `operator[n]` was that `n < vec.size()`. I could have remembered that wrongly. – John Dibling Jul 18 '13 at 16:07
  • @aschepler: I guess it is important to note `*(a.begin()+n)` is doing iterator math, not pointer math. Pointer arithmetic would be defined here but iterator math probably not. – Ben Voigt Jul 18 '13 at 16:32
1

If you don't want use push_back nor construct, consider using the resize method

  • I had to downvote your answer, sorry. It does not address the question. Regarding allocating space for the elements, defining the vector with `std::vector vecX(2);` as in the first part of the OP's code allocates and zeroes the space just as well and without the need for another function call. The question was why the code does what it does when `resize` or an constructor with initial size are *not* used. – The Vee Oct 07 '16 at 19:59