taskinoor taskinoor - 2 months ago 8
C++ Question

Taking reference to vector element before adding more element to vector

Consider this code:

int main()
{

std::vector<std::string> v;

v.push_back("hello");
v.push_back("stack");

std::string &s = v[0];

v.push_back("overflow");

std::cout << s << std::endl;

return 0;
}


After running (using
g++ (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4
) this prints only an empty line,
hello
is not printed. If I comment out
v.push_back("stack");
then a segmentation fault appears.

Now I understand why this is happening. Adding more elements to vector is triggering a grow operation under the hood and my old reference becomes invalid after that. This is not my question.

My question is whether this behavior - modifying a vector or other STL container after taking a reference/pointer - is defined as undefined behavior in C++ standard? If yes, where? If no then what the standard says about this type of situation?

Answer

The act of modifying the container is not prohibited just because you acquired an iterator, reference, or pointer by some means. It is the iterator, reference, or pointer itself that is potentially invalidated.

§23.3.6.6 [vector.modifiers] (includes the push_back member family)

  1. Remarks: Causes reallocation if the new size is greater than the old capacity. If no reallocation happens, all the iterators and references before the insertion point remain valid. If an exception is thrown other than by the copy constructor, move constructor, assignment operator, or move assignment operator of T or by any InputIterator operation there are no effects. If an exception is thrown while inserting a single element at the end and T is CopyInsertable or is_nothrow_move_constructible<T>::value is true, there are no effects. Otherwise, if an exception is thrown by the move constructor of a non-CopyInsertable T, the effects are unspecified.

If no resize happens only references, pointers, and iterators (including the end-iterator) past the insertion point are invalid. Great, but what happens if a reallocation happens? Interestingly, we find that in:

§23.3.6.3 [vector.capacity]

  1. Remarks: Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence. No reallocation shall take place during insertions that happen after a call to reserve() until the time when an insertion would make the size of the vector greater than the value of capacity().

I'm not entirely convinced this completely answers your question, however. If your wondering what happened to the prior memory that occupied the vector, that's up to the standard library, but it no longer contains viable content. The container no longer owns the memory (as far as you know), and neither do you.

Comments