Search code examples
c++stdundefined-behavior

Is Insertion into a vector while also accessing a vector undefined behavior?


Just stumbled upon a post that talked about reference and iterator invalidation on insertion into a vector.

But will accessing a vector by index also result in undefined behavior? Is the below code correct?

std::vector<int> data {0, 1, 2};
// EDIT: Fixing error '... i < data.size(); ...'
for (int i = 0; i < 10; ++i) {
  auto end = data.size();
  // Using 'for (const auto &v : data) {' below seems to be causing segfault
  // on some platforms and not on others, but clearly is wrong use of a reference
  for (int j = 0; j < end; ++j) {
    data.emplace_back(data.at(j) + end);
  }
}

This question stems from: Iterator invalidation rules for C++ containers


Solution

  • The use of indices in a loop while modifying the vector is fine, and it's not directly the issue here. The problem is that you're growing the vector indefinitely. The looping condition tests i < data.size(), which in essence will always be true because the vector size grows faster than i does.

    The undefined behavior arises because you're using signed integers as indices. Once i reaches std::numeric_limits<int>::max() then you have a problem. At this point, executing ++i has undefined behavior according to the C++ standard.

    If you instead use unsigned integers (e.g. std::size_t, or more correctly std::vector<int>::size_type), you no longer have undefined behavior but you instead have an infinite loop. The loop will continue until the vector fails to reallocate and throws std::bad_alloc. If you are not handling this exception then your program will crash.

    Technically, the loop isn't infinite. You're limited by the available RAM (as above), but also the vector's maximum size. If you happen to have endless memory available, the call to emplace_back will eventually throw std::length_error when the vector cannot grow any further.