Example - using vectors

Posted by Nick Gammon on Fri 04 Jul 2003 06:07 AM — 3 posts, 19,363 views.

Australia Forum Administrator #0
Vectors are handy things for simple lists where you want random access (eg. for sorting, shuffling and so on).

The example below illustrates various things you can do with vectors. I have used vectors of strings so I can also play with case-independent sorts, sort descending, appending to each item, and so on.

Notice the difference the case-independent sort makes on the words "the" and "The". For case-independence they are together, otherwise they are at opposite ends of the sentence.




// disable warnings about long names
#ifdef WIN32
  #pragma warning( disable : 4786)
#endif

#include <string>
#include <vector>
#include <iostream>
#include <functional>
#include <iterator>
#include <algorithm>

using namespace std;

// case-independent (ci) string less_than
// returns true if s1 < s2
struct ci_less : binary_function<string, string, bool>
  {

  // case-independent (ci) compare_less binary function
  struct nocase_compare : public binary_function<unsigned char,unsigned char,bool> 
    {
    bool operator() (const unsigned char& c1, const unsigned char& c2) const 
      { return tolower (c1) < tolower (c2); }
    };

  bool operator() (const string & s1, const string & s2) const
    {
  
    return lexicographical_compare 
          (s1.begin (), s1.end (),   // source range
           s2.begin (), s2.end (),   // dest range
                nocase_compare ());  // comparison
    }
  }; // end of ci_less

void showv (const string s, const vector<string> & v)
  {
  cout << s << endl;
  copy(v.begin(), v.end(), ostream_iterator<string>(cout, " "));
  cout << endl << endl;
  } // end of showv

int main (void)
  {
  // vector of strings
  vector<string> v;

  // make a back insert iterator to safely add to the back of the vector
  back_insert_iterator<vector<string> > i(v);
  
// Insert items into the vector. 
// Strictly speaking, the "++" is not needed, as the
// assignment to the iterator is what advances it.

  *i++ = "The";
  *i++ = "quick";
  *i++ = "brown";
  *i++ = "fox";
  *i++ = "jumped";
  *i++ = "over";
  *i++ = "the";
  *i++ = "lazy";
  *i++ = "dog";

  showv ("initial vector...", v);

  // sort ascending
  sort (v.begin (), v.end ());
  showv ("after sort (ascending)...", v);

  // sort descending by using greater function to compare less
  sort (v.begin (), v.end (), greater<string> ());
  showv ("after sort (descending)...", v);

  // sort case-independent by using our own compare-less
  sort (v.begin (), v.end (), ci_less ());
  showv ("after case-independent sort (ascending)...", v);

  // reverse that by doing a "not" on the result
  sort (v.begin (), v.end (), not2 (ci_less ()));
  showv ("after case-independent sort (descending)...", v);
 
  // shuffle the words
  random_shuffle (v.begin (), v.end ());
  showv ("after shuffle...", v);

  // rotate them
  rotate (v.begin (), v.begin () + 1, v.end ());
  showv ("after rotate 1 to the left...", v);

  // reverse their order
  reverse (v.begin (), v.end ());
  showv ("after reverse...", v);

  // add "(" to the beginning of each one
  transform (v.begin (), v.end (),
             v.begin (),
             bind1st (plus<string> (), "("));

  // add ")" to the end of each one
  transform (v.begin (), v.end (),
             v.begin (),
             bind2nd (plus<string> (), ")"));
  showv ("after transforms...", v);

  return 0;
  } // end of main


Output

initial vector...
The quick brown fox jumped over the lazy dog

after sort (ascending)...
The brown dog fox jumped lazy over quick the

after sort (descending)...
the quick over lazy jumped fox dog brown The

after case-independent sort (ascending)...
brown dog fox jumped lazy over quick the The

after case-independent sort (descending)...
The the quick over lazy jumped fox dog brown

after shuffle...
the dog quick over jumped fox The lazy brown

after rotate 1 to the left...
dog quick over jumped fox The lazy brown the

after reverse...
the brown lazy The fox jumped over quick dog

after transforms...
(the) (brown) (lazy) (The) (fox) (jumped) (over) (quick) (dog)






The example also demonstrates "back insertion". One of the nice things about vectors is they can grow as large as you like without having to decide in advance how large that will be, however if you are doing that you need to tell it to insert (and grow) the vector. That is what the back insertion does. Another way would have been:


  vector<string> v (9);

  v [0] = "The";   
  v [1] = "quick"; 
  v [2] = "brown"; 
  v [3] = "fox";   
  v [4] = "jumped";
  v [5] = "over";  
  v [6] = "the";   
  v [7] = "lazy";  
  v [8] = "dog";   


In this case the constructor for the vector is passed the number of items, so that the vector is initialised to the correct size in advance. Once that is done, you can just put the elements into their respective places.

Personally I think that is a bit tedious.

Another approach would be to forget the back inserter and just do a push_back, like this:


  vector<string> v;

  v.push_back ("The");   
  v.push_back ("quick"); 
  v.push_back ("brown"); 
  v.push_back ("fox");   
  v.push_back ("jumped");
  v.push_back ("over");  
  v.push_back ("the");   
  v.push_back ("lazy");  
  v.push_back ("dog");   



I still think that is more coding than the original.

Another approach again is to use a C array, and copy into the STL one. This probably looks the neatest ...


  // vector of strings
  vector<string> v;

  // initial values
  char * s []  = { "The", "quick", "brown", "fox", "jumped", "over", 
                   "the", "lazy", "dog" };

  // copy into vector
  copy (s, &s [ sizeof s / sizeof s [0] ], back_inserter (v));


These examples just show there is more than one way of achieving a result. :)



The back_insert_iterator, back_inserter and push_back, are all variants of the same thing. At the end of the day back_inserter calls push_back, and the back_insert_iterator implements an operator* which also calls push_back. It just depends on which you think is the easiest to code and debug.

In fact, if you look at the way the back_insert_iterator is implemented, the ++ is a no-op, so this would have worked:


  back_insert_iterator<vector<string> > i(v);
  
  *i = "The";
  *i = "quick";
  *i = "brown";
  *i = "fox";
  *i = "jumped";
  *i = "over";
  *i = "the";
  *i = "lazy";
  *i = "dog";


However this is probably not good coding style, as it isn't very obvious from looking at it that the iterator is really progressing to different elements.
Amended on Wed 30 Aug 2006 02:56 AM by Nick Gammon
Australia Forum Administrator #1
Another impressive thing about STL is the error messages it can generate. For example, if you take the above working example, and compile it under gcc, after changing a single character, you get the following error message:




test.cpp: In instantiation of `std::unary_negate<ci_less>':
test.cpp:77: instantiated from here
test.cpp:77: no type named `argument_type' in `struct ci_less'
/usr/include/c++/3.2.2/bits/stl_function.h:278: no type named `argument_type'
in `struct ci_less'
/usr/include/c++/3.2.2/bits/stl_algo.h: In function `void
std::partial_sort(_RandomAccessIter, _RandomAccessIter, _RandomAccessIter,
_Compare) [with _RandomAccessIter =
__gnu_cxx::__normal_iterator<std::string*, std::vector<std::string,
std::allocator<std::string> > >, _Compare = std::unary_negate<ci_less>]':
/usr/include/c++/3.2.2/bits/stl_algo.h:2138: instantiated from `void std::__introsort_loop(_RandomAccessIter, _RandomAccessIter, _Size, _Compare) [with _RandomAccessIter = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Size = int, _Compare = std::unary_negate<ci_less>]'
/usr/include/c++/3.2.2/bits/stl_algo.h:2209: instantiated from `void std::sort(_RandomAccessIter, _RandomAccessIter, _Compare) [with _RandomAccessIter = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Compare = std::unary_negate<ci_less>]'
test.cpp:77: instantiated from here
/usr/include/c++/3.2.2/bits/stl_algo.h:2557: no match for call to `(
std::unary_negate<ci_less>) (std::basic_string<char, std::char_traits<char>,
std::allocator<char> >&, std::basic_string<char, std::char_traits<char>,
std::allocator<char> >&)'
/usr/include/c++/3.2.2/bits/stl_algo.h: In function `const _Tp&
std::__median(const _Tp&, const _Tp&, const _Tp&, _Compare) [with _Tp =
std::basic_string<char, std::char_traits<char>, std::allocator<char> >,
_Compare = std::unary_negate<ci_less>]':
/usr/include/c++/3.2.2/bits/stl_algo.h:2147: instantiated from `void std::__introsort_loop(_RandomAccessIter, _RandomAccessIter, _Size, _Compare) [with _RandomAccessIter = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Size = int, _Compare = std::unary_negate<ci_less>]'
/usr/include/c++/3.2.2/bits/stl_algo.h:2209: instantiated from `void std::sort(_RandomAccessIter, _RandomAccessIter, _Compare) [with _RandomAccessIter = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Compare = std::unary_negate<ci_less>]'
test.cpp:77: instantiated from here
/usr/include/c++/3.2.2/bits/stl_algo.h:124: no match for call to `(
std::unary_negate<ci_less>) (const std::basic_string<char,
std::char_traits<char>, std::allocator<char> >&, const
std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'
/usr/include/c++/3.2.2/bits/stl_algo.h:125: no match for call to `(
std::unary_negate<ci_less>) (const std::basic_string<char,
std::char_traits<char>, std::allocator<char> >&, const
std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'
/usr/include/c++/3.2.2/bits/stl_algo.h:127: no match for call to `(
std::unary_negate<ci_less>) (const std::basic_string<char,
std::char_traits<char>, std::allocator<char> >&, const
std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'
/usr/include/c++/3.2.2/bits/stl_algo.h:131: no match for call to `(
std::unary_negate<ci_less>) (const std::basic_string<char,
std::char_traits<char>, std::allocator<char> >&, const
std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'
/usr/include/c++/3.2.2/bits/stl_algo.h:133: no match for call to `(
std::unary_negate<ci_less>) (const std::basic_string<char,
std::char_traits<char>, std::allocator<char> >&, const
std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'
/usr/include/c++/3.2.2/bits/stl_algo.h: In function `_RandomAccessIter
std::__unguarded_partition(_RandomAccessIter, _RandomAccessIter, _Tp,
_Compare) [with _RandomAccessIter =
__gnu_cxx::__normal_iterator<std::string*, std::vector<std::string,
std::allocator<std::string> > >, _Tp = std::basic_string<char,
std::char_traits<char>, std::allocator<char> >, _Compare =
std::unary_negate<ci_less>]':
/usr/include/c++/3.2.2/bits/stl_algo.h:2147: instantiated from `void std::__introsort_loop(_RandomAccessIter, _RandomAccessIter, _Size, _Compare) [with _RandomAccessIter = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Size = int, _Compare = std::unary_negate<ci_less>]'
/usr/include/c++/3.2.2/bits/stl_algo.h:2209: instantiated from `void std::sort(_RandomAccessIter, _RandomAccessIter, _Compare) [with _RandomAccessIter = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Compare = std::unary_negate<ci_less>]'
test.cpp:77: instantiated from here
/usr/include/c++/3.2.2/bits/stl_algo.h:1910: no match for call to `(
std::unary_negate<ci_less>) (std::basic_string<char, std::char_traits<char>,
std::allocator<char> >&, std::basic_string<char, std::char_traits<char>,
std::allocator<char> >&)'
/usr/include/c++/3.2.2/bits/stl_algo.h:2147: instantiated from `void std::__introsort_loop(_RandomAccessIter, _RandomAccessIter, _Size, _Compare) [with _RandomAccessIter = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Size = int, _Compare = std::unary_negate<ci_less>]'
/usr/include/c++/3.2.2/bits/stl_algo.h:2209: instantiated from `void std::sort(_RandomAccessIter, _RandomAccessIter, _Compare) [with _RandomAccessIter = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Compare = std::unary_negate<ci_less>]'
test.cpp:77: instantiated from here
/usr/include/c++/3.2.2/bits/stl_algo.h:1913: no match for call to `(
std::unary_negate<ci_less>) (std::basic_string<char, std::char_traits<char>,
std::allocator<char> >&, std::basic_string<char, std::char_traits<char>,
std::allocator<char> >&)'
/usr/include/c++/3.2.2/bits/stl_algo.h: In function `void
std::__insertion_sort(_RandomAccessIter, _RandomAccessIter, _Compare) [with
_RandomAccessIter = __gnu_cxx::__normal_iterator<std::string*,
std::vector<std::string, std::allocator<std::string> > >, _Compare =
std::unary_negate<ci_less>]':
/usr/include/c++/3.2.2/bits/stl_algo.h:2075: instantiated from `void std::__final_insertion_sort(_RandomAccessIter, _RandomAccessIter, _Compare) [with _RandomAccessIter = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Compare = std::unary_negate<ci_less>]'
/usr/include/c++/3.2.2/bits/stl_algo.h:2210: instantiated from `void std::sort(_RandomAccessIter, _RandomAccessIter, _Compare) [with _RandomAccessIter = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Compare = std::unary_negate<ci_less>]'
test.cpp:77: instantiated from here
/usr/include/c++/3.2.2/bits/stl_algo.h:2007: no match for call to `(
std::unary_negate<ci_less>) (std::string&, std::basic_string<char,
std::char_traits<char>, std::allocator<char> >&)'
/usr/include/c++/3.2.2/bits/stl_algo.h: In function `void
std::__unguarded_linear_insert(_RandomAccessIter, _Tp, _Compare) [with
_RandomAccessIter = __gnu_cxx::__normal_iterator<std::string*,
std::vector<std::string, std::allocator<std::string> > >, _Tp =
std::basic_string<char, std::char_traits<char>, std::allocator<char> >,
_Compare = std::unary_negate<ci_less>]':
/usr/include/c++/3.2.2/bits/stl_algo.h:2012: instantiated from `void std::__insertion_sort(_RandomAccessIter, _RandomAccessIter, _Compare) [with _RandomAccessIter = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Compare = std::unary_negate<ci_less>]'
/usr/include/c++/3.2.2/bits/stl_algo.h:2075: instantiated from `void std::__final_insertion_sort(_RandomAccessIter, _RandomAccessIter, _Compare) [with _RandomAccessIter = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Compare = std::unary_negate<ci_less>]'
/usr/include/c++/3.2.2/bits/stl_algo.h:2210: instantiated from `void std::sort(_RandomAccessIter, _RandomAccessIter, _Compare) [with _RandomAccessIter = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Compare = std::unary_negate<ci_less>]'
test.cpp:77: instantiated from here
/usr/include/c++/3.2.2/bits/stl_algo.h:1961: no match for call to `(
std::unary_negate<ci_less>) (std::basic_string<char, std::char_traits<char>,
std::allocator<char> >&, std::basic_string<char, std::char_traits<char>,
std::allocator<char> >&)'
/usr/include/c++/3.2.2/bits/stl_heap.h: In function `void
std::__adjust_heap(_RandomAccessIterator, _Distance, _Distance, _Tp,
_Compare) [with _RandomAccessIterator =
__gnu_cxx::__normal_iterator<std::string*, std::vector<std::string,
std::allocator<std::string> > >, _Distance = int, _Tp =
std::basic_string<char, std::char_traits<char>, std::allocator<char> >,
_Compare = std::unary_negate<ci_less>]':
/usr/include/c++/3.2.2/bits/stl_heap.h:268: instantiated from `void std::make_heap(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Compare = std::unary_negate<ci_less>]'
/usr/include/c++/3.2.2/bits/stl_algo.h:2555: instantiated from `void std::partial_sort(_RandomAccessIter, _RandomAccessIter, _RandomAccessIter, _Compare) [with _RandomAccessIter = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Compare = std::unary_negate<ci_less>]'
/usr/include/c++/3.2.2/bits/stl_algo.h:2138: instantiated from `void std::__introsort_loop(_RandomAccessIter, _RandomAccessIter, _Size, _Compare) [with _RandomAccessIter = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Size = int, _Compare = std::unary_negate<ci_less>]'
/usr/include/c++/3.2.2/bits/stl_algo.h:2209: instantiated from `void std::sort(_RandomAccessIter, _RandomAccessIter, _Compare) [with _RandomAccessIter = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Compare = std::unary_negate<ci_less>]'
test.cpp:77: instantiated from here
/usr/include/c++/3.2.2/bits/stl_heap.h:187: no match for call to `(
std::unary_negate<ci_less>) (std::basic_string<char, std::char_traits<char>,
std::allocator<char> >&, std::basic_string<char, std::char_traits<char>,
std::allocator<char> >&)'
/usr/include/c++/3.2.2/bits/stl_heap.h: In function `void
std::__push_heap(_RandomAccessIterator, _Distance, _Distance, _Tp, _Compare)
[with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::string*,
std::vector<std::string, std::allocator<std::string> > >, _Distance = int,
_Tp = std::basic_string<char, std::char_traits<char>, std::allocator<char>
>, _Compare = std::unary_negate<ci_less>]':
/usr/include/c++/3.2.2/bits/stl_heap.h:197: instantiated from `void std::__adjust_heap(_RandomAccessIterator, _Distance, _Distance, _Tp, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Distance = int, _Tp = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _Compare = std::unary_negate<ci_less>]'
/usr/include/c++/3.2.2/bits/stl_heap.h:268: instantiated from `void std::make_heap(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Compare = std::unary_negate<ci_less>]'
/usr/include/c++/3.2.2/bits/stl_algo.h:2555: instantiated from `void std::partial_sort(_RandomAccessIter, _RandomAccessIter, _RandomAccessIter, _Compare) [with _RandomAccessIter = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Compare = std::unary_negate<ci_less>]'
/usr/include/c++/3.2.2/bits/stl_algo.h:2138: instantiated from `void std::__introsort_loop(_RandomAccessIter, _RandomAccessIter, _Size, _Compare) [with _RandomAccessIter = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Size = int, _Compare = std::unary_negate<ci_less>]'
/usr/include/c++/3.2.2/bits/stl_algo.h:2209: instantiated from `void std::sort(_RandomAccessIter, _RandomAccessIter, _Compare) [with _RandomAccessIter = __gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, _Compare = std::unary_negate<ci_less>]'
test.cpp:77: instantiated from here
/usr/include/c++/3.2.2/bits/stl_heap.h:107: no match for call to `(
std::unary_negate<ci_less>) (std::basic_string<char, std::char_traits<char>,
std::allocator<char> >&, std::basic_string<char, std::char_traits<char>,
std::allocator<char> >&)'
make: *** [test.o] Error 1




How's that? Not bad eh?


To generate that I changed the line:


sort (v.begin (), v.end (), not2 (ci_less ()));


to


sort (v.begin (), v.end (), not1 (ci_less ()));


Notice, the change of "not2" to "not1".

It shows, that even if you get a really lengthy error message, to stay calm - maybe there is only a minor coding bug. ;)

However the gratifying thing is that the line number reported in the error message (77) was in fact the line with the error on it.

Amended on Fri 04 Jul 2003 07:51 AM by Nick Gammon
Australia Forum Administrator #2
Removing things from vectors

Removing things from the middle of a vector is not as simple as it might seem, because two things need to happen:

  1. Everything after the thing(s) being removed need to be shuffled along
  2. The end needs to be adjusted to reflect its new size


This is because vectors are stored linearly, so you can randomly access their contents. If you use the remove_if algorithm, without adjusting the vector length, then you will get the same length vector, and with some of the original things duplicated, like this:




// disable warnings about long names
#ifdef WIN32
  #pragma warning( disable : 4786)
#endif

#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <functional>

using namespace std;

#define NUMITEMS(x) (sizeof(x) / sizeof(x[0]))

int main (void)
  {

  // vector of strings
  vector<string> v;

  char * cs [] = { "the", "dog", "and", "the", "cat", "went",
    "to", "the", "shop" };

  // set up vector
  copy (cs, & cs [ NUMITEMS (cs) ], back_inserter (v));

  // remove the word "the"
  remove_if (v.begin (), v.end (), bind2nd (equal_to<string> (), "the"));

  // display results
  copy (v.begin(), v.end(), ostream_iterator<string> (cout, " "));
  cout << endl;

  return 0;
  } // end of main


Output

dog and cat went to shop to the shop





What we need to do is retain the result from the remove_if, which will be the end of the new sequence, which we can then pass to the vector's erase function, like this ...




// disable warnings about long names
#ifdef WIN32
  #pragma warning( disable : 4786)
#endif

#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <functional>

using namespace std;

#define NUMITEMS(x) (sizeof(x) / sizeof(x[0]))

int main (void)
  {

  // vector of strings
  vector<string> v;

  char * cs [] = { "the", "dog", "and", "the", "cat", "went",
    "to", "the", "shop" };

  // set up vector
  copy (cs, & cs [ NUMITEMS (cs) ], back_inserter (v));

  // iterator to hold the new end
  vector<string>::iterator i;

  // remove the word "the"
  i = remove_if (v.begin (), v.end (), bind2nd (equal_to<string> (), "the"));

  // adjust vector size
  v.erase (i, v.end ());

  // display results
  copy (v.begin(), v.end(), ostream_iterator<string> (cout, " "));
  cout << endl;

  return 0;
  } // end of main


Output

dog and cat went to shop





A little more elegantly, we can combine the remove and erase into a single line, to save defining a temporary iterator, like this:




// disable warnings about long names
#ifdef WIN32
  #pragma warning( disable : 4786)
#endif

#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <functional>

using namespace std;

#define NUMITEMS(x) (sizeof(x) / sizeof(x[0]))

int main (void)
  {

  // vector of strings
  vector<string> v;

  char * cs [] = { "the", "dog", "and", "the", "cat", "went",
    "to", "the", "shop" };

  // set up vector
  copy (cs, & cs [ NUMITEMS (cs) ], back_inserter (v));

  // remove the word "the" and adjust the length as well
  v.erase (remove_if (v.begin (), v.end (), bind2nd (equal_to<string> (), "the")),
         v.end ());

  // display results
  copy (v.begin(), v.end(), ostream_iterator<string> (cout, " "));
  cout << endl;

  return 0;
  } // end of main


Output

dog and cat went to shop