1

While debugging my code, I've noticed a change in stored iterator, pointed to begin(), after every 4 or 5 call to += operator on a string (what it points to, isn't even in the string itself!). Here's what my code looks like:

for (auto ch=word.begin(); ch!=word.end(); ++ch) {
  // on a condition, the following loop starts
  // ch == word.begin()
  for (int i=0; ...) {
    string_view tmp = arr[i];
    word += tmp;
  }
  // ch is no longer equal to word.begin()
}

While reassigning ch to word.begin() after second loop fixed my issue, I'm wondering why this has happened. I couldn't find anything on the internet.

etzl
  • 105
  • 1
  • 8
  • You may not modify a string while iterating over it, because those modifications may cause the underlying storage to be reallocated (invalidating any iterators). – Karl Knechtel Aug 19 '21 at 11:56
  • If/when the string is reallocated all iterators/pointers to the underlying data is invalidated. – super Aug 19 '21 at 11:58
  • Ask yourself: If arrays are always a fixed size, and the size of word is increasing, what happens when it needs to grow bigger than the array it is using? – NathanOliver Aug 19 '21 at 11:59
  • I can see OPs problem, search these 2 page for __invalid__ [std::string::clear](https://en.cppreference.com/w/cpp/string/basic_string/clear) and [std::string::operator+=](https://en.cppreference.com/w/cpp/string/basic_string/operator%2B%3D) Most of the modifying operations have the invalidation clause missing. – Richard Critten Aug 19 '21 at 12:02
  • " I couldn't find anything on the internet." Really? When I **literally copy and paste** your question title [into a search engine](https://duckduckgo.com/?q=Is+std%3A%3Astring%3A%3Abegin()+iterator+invalid+after+%2B%3D+operator%3F), the [second result I get](https://www.geeksforgeeks.org/iterator-invalidation-cpp/) shows an example of the problem (caused by pushing back onto a vector, which is fundamentally the same situation) with a detailed explanation. Or you could try something like[ `c++ tutorial iterator invalidation`](https://duckduckgo.com/?q=c%2B%2B+tutorial+iterator+invalidation). – Karl Knechtel Aug 19 '21 at 12:02
  • I didn't notice it has to reallocate. Thanks for your clarification. – etzl Aug 19 '21 at 12:17

1 Answers1

3

When you extend cointainers like vector or string sometimes they may to reallocate their memory to new location - so it change address. They need continuous memory, beacuse aren't list with pointer to next element.

Iterator move through continous memory addresses. Next element is address+1.

So, at begining, your first element in string is stored in address X. But you add few letters, what results in reallocating container to new location. Now, your string isn't stored in address X, but address Y. Despite this, your iterator still point to address X.

You can't use iterator without reinitallizing, when adding or removing elements, because these operation cause iterators to be invalidated.

  • _"...because these operation cause iterators to be invalidated"_...No, this is not always true, it's a generalization. There are container specific rules/conditions/etc: [see a list here](https://stackoverflow.com/a/54004916). (Although `std::string` is not mentioned there...) – JHBonarius Aug 19 '21 at 13:01