-1

Pretty simple question, but why is it that when you call

std::vector<int> vec;
vec.reserve(100);
vec[89] = 99; // vector subscript out of range.-

You are not allowed to access elements 0-99 of the vector? Doesn't make a lot of sense considering that reserving increased capacity of the vector (allocated a new array of that size) and such you should be able to access those elements even though they would be empty or null to start.

I understand that if you do it the following way:

std::vector<int> vec(99, 0);
vec[89] = 99;

You would be allowed to access the elements because they will be initialized to 0, however, you can't resize a vector with default values like this more than once other than initially through the constructor.

With arrays, one can do:

int[] arr = new int[100];
arr[89] = 99;

Granted you would have to write the resizing yourself.

arr1 = new int[200]
memcpy (arr1, arr, 100);
arr = arr1;
arr[90] = 100;

Is there any way to treat std::vector like arrays that resize themselves once you reach a certain capacity?

Francisco Aguilera
  • 3,099
  • 6
  • 31
  • 57
  • 3
    Given that a `vector` can hold more than just simple `int`s (like `string`, for example), it makes sense. If you have a `vector` of `string`s, those strings haven't had their constructors run, and thus would be illegal to access. – Cornstalks Apr 29 '15 at 19:36
  • 1
    `int` has vacuous initialization, hence your line is fine. However, some object types require initialization to be alive.Passing `vec[89]` to an assignment operator of a class without a trivial default constructor is UB. – Columbo Apr 29 '15 at 19:40
  • 5
    "however, you can't resize a vector with default values" see [vector.resize](http://www.cplusplus.com/reference/vector/vector/resize/) – ryanpattison Apr 29 '15 at 19:42
  • @Columbo, every type has at least, a default constructor. – Francisco Aguilera Apr 29 '15 at 19:46
  • 2
    @FranciscoAguilera `struct foo { foo(int) {} };` doesn't have a default constructor. – juanchopanza Apr 29 '15 at 19:49
  • 2
    Or more obviously `class foo { foo() = delete; };` – MSalters Apr 29 '15 at 22:52

3 Answers3

8

You should not mix up resize and reserve

  • reserve allocates space (if needed) but doesn't initialize it, that way when you insert new elements only the construction is called and no realocation is done (until you used all the reserved space)
  • resize allocates space (if needed) and initialize it by calling the constructor.

Therefore when you reserve space, the new values are not accessible until they have been initialized/constructed by doing an operation like push_back or resize

Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
Amxx
  • 3,020
  • 2
  • 24
  • 45
3

Vectors are like arrays that resize themselves once you reach a certain capacity, if you use insert and push_back and other such functions.

You complain about vec.reserve(100); because it calls all of the constructors, and then imply you want it to work like int[] arr = new int[100];, but you seem to be overlooking the fact that new int also calls all of the destructors. They do the same thing here.

you can't resize a vector with default values like this more than once other than initially through the constructor

There's vector::resize which resizes the array and default constructs any new ones. If you want to "reset" existing ones, simply use std::fill.

The purpose of vector::reserve is to make insert and push_back not do unnecessary reallocations. Which is a neat trick that raw arrays can't easily duplicate. This is extra functionality, not missing functionality.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
3

C++ is an abstraction, and in that abstraction those elements aren't "null" or "empty": they simply do not exist. Only space for them exists.

Now, in the case of int on many practical implementations, if you look at the memory then you can't really tell the difference. You could access that memory. But then you're violating the contract of vector, and this is going to hit you as soon as you perform mutating operations on the container: it's going to take your memory away from you and it's not going to carry your "data" along with it.

You don't gain anything by refusing to properly construct actual elements.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055