1

I just realized that I can access object members of my empty object vector list. I thought vector.reserve(nmb) just reserves the required memory (kind of nmb*sizeof(object)).

#include <iostream>
#include <vector>



class Car {

    public: int tires = 4;

    Car(void) {
        std::cout << "Constructor of Car" << std::endl;
    }
};

int main()
{
    std::vector<Car> carList;
    carList.reserve(20);
    std::cout << "Car tires: " << carList[0].tires << std::endl;
    std::cout << "Now comes the emplace_back:" << std::endl;
    carList.emplace_back();
    std::cout << "Car tires: " << carList[0].tires << std::endl;

    //Car carArray[20];
    //std::cout << "Car tires: " << carArray[0].tires << std::endl;

    return 0;
}

gives me:

Car tires: 0                                                                                                                                        
Now comes the emplace_back:                                                                                                                         
Constructor of Car                                                                                                                                  
Car tires: 4                                                                                                                                        

...Program finished with exit code 0 

Why can I access members of not yet initialized objects? Thank you.

muella91
  • 189
  • 1
  • 2
  • 12
  • because memory for these objects are reserved in the vector by `carList.reserve(20);`, but this memory is not initialized, so that's why you have thrash values – Raffallo Feb 18 '20 at 08:33

2 Answers2

4

Because the operator[] does not do any boundary checks (and just translates to some pointer arithmetic when you compile an optimized binary). This is so std::vector can be as efficiently used as a plain C array.

The 0 that you read is just what happens to be in memory where the vector has reserved space on the heap. Note that the operating system initializes the program's memory with 0 as a security measure (so you cannot peek on old data). If your applications runs a bit longer and pages are recycled, you can also observe other garbage values.

You could try at() instead which will check for boundaries.

ypnos
  • 50,202
  • 14
  • 95
  • 141
  • Okay, I understand than I can access the memory and write any bullshit in it. But I do not understand why I can access the member tires of a object that is not initialized. I edited my example and added a constructor to make it more clear. – muella91 Feb 18 '20 at 08:42
  • 1
    Please note that accessing this reserved memory has undefined behavior. One is not allowed to use it, even if your explanation is a likely result in practice. – walnut Feb 18 '20 at 09:02
  • 1
    @muella91 The access to a struct/class member is again, in the end, just pointer arithmetic. The compiler expects you to know what you are doing; it produces dumb but effective machine code. It is your task to not write code that leads to undefined behavior. – ypnos Feb 18 '20 at 09:08
1

Accessing elements of a std::vector outside its size (not its capacity) has undefined behavior.

Undefined behavior means that there is no guarantee that anything specific will happen in general. What exactly happens will depend on the particular implementation of the compiler and the standard library.

One likely behavior was mentioned by @ypnos, but (any) other behavior would also be permissible by the C++ standard and possible depending on how exactly the standard library implements std::vector and how exactly the compiler optimizes.

walnut
  • 21,629
  • 4
  • 23
  • 59