C++: Erase-Remove Idiom

Erase-remove idiom is a common technique to eliminate the elements from a C++ STL container which satisfies a particular condition.

We can do the hand written loop to remove the elements from the container. For e.g. if you want to remove an element vector you can do something as below. (note erasing element from a C++ container within a standard for or while loop with simple iterator++ will end up undefined result)

vector::iterator it = vec.begin();
while(it != vec.end())
     if( *it == 5 )
         it = vec.erase(it); // Remove and take the return of the erase function to safely reassign
     else
         ++it;

The above code is simple as it appears, it simply iterate through the elements and find if a match there for the value then remove it from the container. And it takes back the value returned form erase where it returns the iterator of the next element. If no more elements, it will vector::end

Now, the containers will have different implementations for the same function. A map::erase return void. So it’s difficult to give a single and easy strategy for each type of containers.

remove is a handy function defined in algorthm It’s easy to get confused to know what it does and distinguish between erase. remove remove (move) the elements from the given range. Mostly push it towards the end of the container. The function returns an iterator to the location where the moved elements located within the container. It essentially won’t remove the elements as such from the container. Here is the sample demo of using remove

// remove algorithm example
#include 
using namespace std;

int main ()
{
  int data[] = {10,20,30,30,20,10,10,20};      // 10 20 30 30 20 10 10 20

  // bounds of range:
  int* pbegin = data;                          // ^
  int* pend = data+sizeof(data)/sizeof(int);   // ^                       ^

  pend = remove (pbegin, pend, 20); // 10 30 30 10 10 ?  ?  ?
                                    // ^              ^

  return 0;
}

Now this handy function has an alternative version to give a comparator function which can accept the object of the type specified for the container. Inside the function, you can make decision to remove or not by specifying in the return value. In simple words, rather giving a comparison hard coded value, we’ll give a function to make decision for us. See the documentation and example here.

Erase-Remove tequenique is accomplished in following ways.
1. Move the elements to be removed to the end with the help of remove function
2. Take the return of remove and pass to the erase function as beginning and containers::end as end.
3. Finally the contianer will contains the elements which are not satisfying the comparator function/value.

#include  // the general-purpose vector container
#include  // remove and remove_if

bool is_odd(int i) { // unary predicate returning true if and only if the argument is odd
  return i % 2;
}
bool is_even(int i) { // unary predicate returning true if and only if the argument is even
  return !is_odd(i);
}

int main() {
  using namespace std;
  int elements[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  // create a vector that holds the numbers from 0-9.
  vector v(elements, elements + 10); 

  // use the erase-remove idiom to remove all elements with the value 5
  v.erase(remove(v.begin(), v.end(), 5), v.end()); 

  // use the erase-remove idiom to remove all odd numbers
  v.erase( remove_if(v.begin(), v.end(), is_odd), v.end() );

  // use the erase-remove idiom to remove all even numbers
  v.erase( remove_if(v.begin(), v.end(), is_even), v.end() );
}

Reference:
Erase-remove idiom

WinDBG – Visualizing STL containers and strings

With the help of STL extension, this extension can’t visualize each and every containers or classes in STL, rather it displays the mostly used string, wstring, vector<[w]string>, list<[w]string>

for more information give !stl -? in WinDBG input or check in the help file.
See the example below and the output in the debugger console.

// SampleSTL.cpp : Defines the entry point for the console application.
// Compiled with Microsoft Visual C++ 9.0 compiler

#include "stdafx.h"
#include 
#include 
#include

#include 

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{

	string str1("Quick");
	string str2("Brown" );

	string str3 = str1 + " " + str2;

	vector vec;

	vec.push_back(str1);
	vec.push_back(str2);
	vec.push_back(str3);

	list lst;

	lst.push_back( str1 );
	lst.push_back( str2 );
	lst.push_back( str3 );

	for( vector::iterator iter = vec.begin(); iter != vec.end(); ++iter)
		cout << (*iter).c_str() << endl;

	cout <::iterator iter = lst.begin(); iter != lst.end(); ++iter)
		cout << (*iter).c_str() << endl;

	return 0;
}

WinDGB output

0:000> !stl str1
[da 0x16fb18]
0016fb18  "Quick"

0:000> !stl str2
[da 0x16faf0]
0016faf0  "Brown"

0:000> !stl str3
[da 0x16fac8]
0016fac8  "Quick Brown"

0:000> !stl vec
	Element 0
[da 0x558358]
00558358  "Quick"
	Element 1
[da 0x558378]
00558378  "Brown"
	Element 2
[da 0x558398]
00558398  "Quick Brown"

0:000> !stl lst
The list has 00000003 elements
	Element 0
[da 0x558400]
00558400  "Brown"
	Element 1
[da 0x558468]
00558468  "Quick Brown"
	Element 2
[da 0xffffffffcdcdcdcd]
cdcdcdcd  "????????????????????????????????"
cdcdcded  "????????????????????????????????"
cdcdce0d  "????????????????????????????????"
cdcdce2d  "????????????????????????????????"
cdcdce4d  "????????????????????????????????"
cdcdce6d  "????????????????????????????????"
cdcdce8d  "????????????????????????????????"
cdcdcead  "????????????????????????????????"
cdcdcecd  "????????????????????????????????"
cdcdceed  "????????????????????????????????"
cdcdcf0d  "????????????????????????????????"
cdcdcf2d  "????????????????????????????????"