Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Range-base for and insert on a vector C++11

Is it possible to change the size of a vector in C++11 while iterating over it? Clearly the iterator will be invalidated, but can the following clean syntax still be used?

std::vector<some_type> vec;
for(auto elem : vec) {
   if(condition(elem)) {
      new_elem = function(elem);
      vec.insert(iterator_associated_with_elem+1, new_elem);
   }
   //Don't insert on condition(new_elem)
}

If not, what is the cleanest code to accomplish this task?

like image 790
user14717 Avatar asked Apr 09 '14 16:04

user14717


People also ask

Are there range-based for loops in C?

Range-based for loop (since C++11) Executes a for loop over a range. Used as a more readable equivalent to the traditional for loop operating over a range of values, such as all elements in a container.

How do you use the Range function in CPP?

Use the range-based for statement to construct loops that must execute through a range, which is defined as anything that you can iterate through—for example, std::vector , or any other C++ Standard Library sequence whose range is defined by a begin() and end() .

What is vector in C ++ 11?

A vector is a sequence container class that implements dynamic array, means size automatically changes when appending elements. A vector stores the elements in contiguous memory locations and allocates the memory as needed at run time.


2 Answers

No, you can't. The standard mandates that the raged-based for behaves like a given algorithm. This algorithm uses iterators, which get invalidated when you modify the vector.

The simplest way for me is to to use iterators. Note that when we insert, we also reassign the iterator so that we always have a valid iterator:

auto it = vec.begin();
while(it < vec.end()) {
  if (condition(*it)) {
    new_elem = function(*it);
    it = vec.insert(it + 1, new_elem);
  }
  ++it;
}
like image 105
bolov Avatar answered Nov 14 '22 23:11

bolov


No, you cannot use this trick, because there is an iterator behind your range loop. Once that iterator is invalidated, you cannot reference it again.

You can use this construct if you exit the loop immediately after the insertion. Otherwise, you need to use an index-based loop that starts at the back, and goes down to zero to avoid "seeing" elements that have been inserted during the execution of the loop.

std::vector<some_type> vec;
for(int i = vec.size()-1 ; i >= 0 ; i--) {
   const some_type& elem(vec[i]);
   if(condition(elem)) {
      vec.insert(vec.begin()+i+1, function(elem));
   }
   //Don't insert on condition(new_elem)
}
like image 20
Sergey Kalinichenko Avatar answered Nov 15 '22 01:11

Sergey Kalinichenko