Finding Stuff in Modern C++

I recently had a co-worker ask me what the best way to find an object matching certain criteria in an STL vector. We talked about the “old-school” ways of doing that, like a for loop from zero to the number of items, or a for loop using the being and end iterators. Each of these would do the comparison and then break out of the loop if a match was found. Now these ways work just fine, but there are some newer, more “modern” methods of accomplishing the same things that use STL algorithms. In case you haven’t seen them before I thought I would share…

The first method uses a structure/class to wrap the comparison function and is usually called a “functor”. Essentially this is just an object that implements operator(), which allows you to treat the object somewhat like a function. (And you can pass it to other functions like STL algorithms.)

The second method uses the more modern “lambda” function syntax. It allows you to just define the comparison function right inline with the code. This is the one that I prefer because it keeps the comparison logic with the calling of the find algorithm. I think one of the most important aspects of good code is that it’s easy to follow and understand: you shouldn’t have to go skipping all over the code to figure out what some piece of code is doing.

Of course at first glance, a programmer who is unfamiliar with either of these methods is going to respond “huh?” But once you get used to seeing a functor or a lambda expression, they become pretty easy to read and understand.

So without further ado, on to the code, which demonstrates a very simple example of each method:

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

using namespace std;

class TestObject
{
public:
  TestObject( const string& n, int v ) : m_name( n ), m_value( v ) {}
  const string name() const { return m_name; }
  int value() const { return m_value; }
private:
  string m_name;
  int m_value;
};

struct is_match
{
public:
  is_match( const string& f ): m_value_to_find( f ) {}
  int operator()(const TestObject& currentItem) { return currentItem.name() == m_value_to_find; }
private:
  string m_value_to_find;
};

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

  v.push_back( TestObject( "Joe", 1 ) );
  v.push_back( TestObject( "Fred", 2 ) );
  v.push_back( TestObject( "Jim", 3 ) );
  v.push_back( TestObject( "Sally", 4 ) );

  // Finding the object with a lambda function
  string value_to_find = "Fred";
  vector::iterator foundObjectIter = find_if(
    begin(v),
    end(v),
    [value_to_find](TestObject& currentItem){ return currentItem.name() == value_to_find; }
    );
  printf( "%s: %d\n", foundObjectIter->name().c_str(), foundObjectIter->value() );

  // Finding the object with a functor
  value_to_find = "Sally";
  foundObjectIter = find_if(
    begin(v),
    end(v),
    is_match( value_to_find )
    );
  printf( "%s: %d\n", foundObjectIter->name().c_str(), foundObjectIter->value() );
}

Leave a Reply

Your email address will not be published. Required fields are marked *

Complete the following to verify your humanity: * Time limit is exhausted. Please reload CAPTCHA.

This site uses Akismet to reduce spam. Learn how your comment data is processed.