c++c++11vector

Why I cannot take a alias to a std::vector element?


On the slide 6 at Rust for C++ programmers, there is this code:

#include <iostream>
#include <vector>
#include <string>

using namespace std;

int main()
{
    vector<string> v;
    v.push_back("Hello");

    string& x = v[0];
    v.push_back("world");

    cout << x << endl;
    return 0;
}

Running it I got:

g++ --std=c++11 main.cpp -I . -o main
./main
P▒▒o▒Y ▒▒2.▒8/.▒H/.▒H/.▒X/.▒X/.▒h/.▒h/.▒x/.▒x/.▒▒/.
@▒▒
...

And it keeps going for much more stuff. I found some question about aliases and vectors as:

  1. int vs const int&
  2. Changing things from a vector

But I could not figure out why the alias is not working based on them. I looked over the http://en.cppreference.com/w/cpp/container/vector, about the vector definition, however it does just seem to be continue memory allocated on the disk. I understand the string Hello and world are allocated somewhere on the data member of the program, as on the assembly here by g++ main.cpp -S:

...
.lcomm _ZStL8__ioinit,1,1
    .def    __main; .scl    2;  .type   32; .endef
    .section .rdata,"dr"
.LC0:
    .ascii "Hello\0"
.LC1:
    .ascii "world\0"
    .text
    .globl  main
    .def    main;   .scl    2;  .type   32; .endef
    .seh_proc   main
main:
...

If I do not push the second element world, the program correctly runs. Therefore why the alias is loosing the reference to the first vector element after the second push?


Solution

  • When the method push_back was called the vector can reallocate the used memory and as result the reference becomes invalid.

    You could reserve enough memory before adding new elements to the vector. In this case the reference will be valid. For example

    vector<string> v;
    v.reserve( 2 );
    
    v.push_back("Hello");
    
    string& x = v[0];
    v.push_back("world");
    

    Here is a demonstrative program

    #include <iostream>
    #include <vector>
    #include <string>
    
    int main() 
    {
        std::vector<std::string> v;
        v.reserve( 2 );
    
        v.push_back("Hello");
    
        std::string& x = v[0];
        v.push_back("world");
    
        std::cout << x << ' ' << v[1];
        std::cout << std::endl;
    
        return 0;
    }
    

    Its output is

    Hello world