c++11stdvectorassignment-operator

Directly assigning to a std::vector after reserving does not throw error but does not increase vector size


Let's create a helper class to assist visualizing the issue:

class C
{
int ID = 0;

public:
C(const int newID)
{
    ID = newID;
}

int getID()
{
    return ID;
}
};

Suppose you create an empty std::vector<C> and then reserve it to hold 10 elements:

std::vector<C> pack;
pack.reserve(10);
printf("pack has  %i\n", pack.size()); //will print '0'

Now, you assign a new instance of C into index 4 of the vector:

pack[4] = C(57);
printf("%i\n", pack[4].getID()); //will print '57'
printf("pack has  %i\n", pack.size()); //will still print '0'

I found two things to be weird here:

1) shouldn't the assignment make the compiler (Visual Studio 2015, Release Mode) throw an error even in Release mode?

2) since it does not and the element is in fact stored in position 4, shouldn't the vector then have size = 1 instead of zero?


Solution

  • Undefined behavior is still undefined. If we make this a vector of objects, you would see the unexpected behavior more clearly.

    #include <iostream>
    #include <vector>
    
    struct Foo {
      int data_ = 3;
    };
    
    int main() {
      std::vector<Foo> foos;
      foos.reserve(10);
      std::cout << foos[4].data_; // This probably doesn't output 3.
    }
    

    Here, we can see that because we haven't actually allocated the object yet, the constructor hasn't run.

    Another example, since you're using space that the vector hasn't actually started allocating to you, if the vector needed to reallocate it's backing memory, the value that you wrote wouldn't be copied.

    #include <iostream>
    #include <vector>
    
    int main() {
      std::vector<int> foos;
      foos.reserve(10);
      foos[4] = 100;
      foos.reserve(10000000);
      std::cout << foos[4]; // Probably doesn't print 100.
    }