-3

So I saw this question, which basically says that references and iterators are invalidated together.

I get why iterators are invalidated in certain cases, but why are references invalidated?

From a practical standpoint, I don't see why this is required.

Was it just a design decision or is there some practical reason?

EDIT: To clarify, as far as I understand the underlying structure, it's just pointers to the data that will need to be reallocated (the data (and thus the reference to it) can remain intact). Right?

Some test code:

#include <vector>
#include <iostream>
using namespace std;

int main()
{
    vector<string> yourVect;
    yourVect.push_back("def");
    vector<string>::iterator iter = yourVect.begin();
    const string& ref = *iter;
    yourVect.insert(yourVect.begin(), "abc");
    cout << ref << endl; // !! --- doesn't work - why ?? --- !!
    cout << *iter << endl; // obviously doesn't work
}
Community
  • 1
  • 1
  • the vector can be reallocated – sashoalm Feb 23 '13 at 21:20
  • What do you think your reference is "referencing" when the underlying dynamic allocation it was initialized to is wiped out from under it? – WhozCraig Feb 23 '13 at 21:20
  • 1
    I don't understand, how can you move objects to a new location after a reallocation and still expect the old ones to still be there?! – user541686 Feb 23 '13 at 21:27
  • @Dukeling See Matteo's updated answer. References are more restrictive and play by considerably tighter rules than pointers. And what you're suggesting would not be valid for a pointer either, so I still don't see why you think it would be supported by a reference. There *are* some containers that support live references in the manner your describing, but a vector isn't one of them. See a [`std::deque`](http://en.cppreference.com/w/cpp/container/deque) for such a container, but then only when the inserts are on either end. – WhozCraig Feb 23 '13 at 21:33

1 Answers1

4

If you insert a string at the beginning of your vector all the data has to be moved forward of one place, and if the capacity of the vector is exhausted, the vector will have to reallocate.

So, at best the reference will refer now to different data, at worst it will refer to an invalid memory location: if the vector reallocates, a new memory block is allocated, the old data is copied1 in the new block and the old block is deallocated; since all the old references point to memory locations inside the old block, they will all be invalid.

The guarantees regard the "worst case", that's why it's not guaranteed that, after an insert operation, the references will still be valid. Or, to say it in another way, insertion in a vector may invalidate iterators and references.

Also, I don't see why you think there's a substantial difference in this behavior between references and iterators - a vector iterator is typically just a pointer to the referenced vector position (often hidden inside an implementation-defined class), so it's more or less the same as the reference.


  1. IIRC in C++11 actually they are "moved" (as in std::move); this doesn't change the fact that the old references will keep pointing to then-deallocated memory.
Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
  • @Dukeling: see edit to answer (in particular, the second paragraph). – Matteo Italia Feb 23 '13 at 21:27
  • @Dukeling: yes, that's actually one of the points of `vector` (one big piece of sequential memory instead of a separated memory block for each object). If instead you want a vector of pointers you just have to ask for it (create a `vector`); by the way, in Boost there are handy classes to manage the lifetime of objects stored in a `vector` of pointers. – Matteo Italia Feb 23 '13 at 21:35
  • 2
    @Dukeling It is mandated by the standard to be so. specifically in C++11 § 23.3.6.1p1 *"The elements of a vector are stored contiguously, meaning that if v is a vector where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size()."* – WhozCraig Feb 23 '13 at 21:37
  • This insert should push to the first position of the vector, which already exists, and not force the vector to reallocate, shouldn't it? In that case, why is the reference invalidated? Not looking for a guarantee, rather than the actual behaviour. The reference. Even though the value of the string underneath is changed ("def" -> "abc"), the String instance should still be the same, as far as I understand, since copy/move is invoked on the already existing instance. – Bozhidar Atanasov Jan 21 '23 at 10:24
  • When you push to the first position, all the elements after it are shifted forward, and, if the vector capacity is already all used, the last element has no place to go, so it is forced to reallocate. – Matteo Italia Jan 21 '23 at 23:27