Reputation: 9466
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:
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?
Upvotes: 3
Views: 1673
Reputation: 311058
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
Upvotes: 4
Reputation: 36617
push_back()
resizes the vector (that's intrinsic in adding an element to it).
That invalidates all iterators, pointers, and references that refer to elements of that vector.
Accessing elements of a vector through an invalidated iterator, pointer, or reference (i.e. that were valid before the resizing operation, but not after) gives undefined behaviour.
x
is invalidated by the call of push_back()
that occurs after its initialisation, and before the output statement
Upvotes: 3
Reputation: 816
When you do the second push_back iterators and references should be assumed to be invalidated. The vector may probably resize its data block - most likely at another memory location.
As such the variable reference x is referencing unallocated memory which subsequently leads to undefined behavior.
Upvotes: 7