The following code, on my system, shows the effect of the undefined behavior.
#include <deque>
#include <iostream>
int main()
{
std::deque<int> v1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
for (auto e : v1) std::cout << e << ' ';
std::cout << std::endl;
int& a = v1[1];
int& b = v1[2];
int& c = v1[3];
std::cout << a << ' ' << b << ' ' << c << std::endl;
std::deque<int>::iterator it = v1.insert(v1.begin() + 2, -1);
for (auto e : v1) std::cout << e << ' ';
std::cout << std::endl;
v1[7] = -3;
std::cout << a << ' ' << b << ' ' << c << std::endl;
return a;
}
Its output for me is:
1 2 3 4 5 6 7 8 9 10
2 3 4
1 2 -1 3 4 5 6 7 8 9 10
-1 3 4
If the references a
, b
, and c
, were still valid, the last line should have been
2 3 4
Please, do not deduce from this that a
has been invalidated while b
and c
are still valid. They're all invalid.
Try it out, maybe you are "lucky" and it shows the same to you. If it doesn't, play around with the number of elements in the containar and a few insertions. At some point maybe you'll see something strange as in my case.
Addendum
The ways std::deque
s can be implemented all makes the invalidation mechanism a bit more complex than what happens for the "simpler" std::vector
. And you also have less ways to check if something is actually going to suffer from the effect of undefined behavior. With std::vector
, for instance, you can tell if undefined behavior will sting you upon a push_back
; indeed, you have the member function capacity
, which tells if the container has already enough space to accomodate a bigger size
required by the insertion of further elements by means of push_back
. For instance if size
gives 8, and capacity
gives 10, you can push_back
two more elements "safely". If you push one more, the array will have to be reallocated.