23

I'm looking for practical and educational samples of C++ / STL code fitting in few lines. My actual favorites are:

  1. Empty a vector freeing its reserved memory:

    vector <...>().swap (v)
    

    (swap with a temporary)

  2. Copy a map to a vector:

    map<T1, T2> myMap;
    vector< pair<T1, T2> > myVec(myMap.begin(), myMap.end());
    // or
    myVec.assign(myMap.begin(), myMap.end());
    
  3. Custom, non-boost split:

    vector<string> &mysplit(const string &s, char delim, vector<string> &elems) {
        stringstream ss(s);
        string item;
        while(getline(ss, item, delim)) { elems.push_back(item); }
        return elems;
    }
    

8 Answers8

13

My favorite is copying containers to the output: And copying the input stream into a container.

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

int main()
{
    std::vector<int>   data;
    std::copy(std::istream_iterator<int>(std::cin),
              std::istream_iterator<int>(),
              std::back_inserter(data)
             );

    std::copy(data.begin(),data.end(),
              std::ostream_iterator<int>(std::cout,"\n")
             );
}
Martin York
  • 257,169
  • 86
  • 333
  • 562
7

The following idiom is needed to actually remove the elements removed by remove() or remove_if():

vector<int> v;
...
v.erase(remove(v.begin(), v.end(), 42), v.end());

remove() and remove_if() just slide non-removed elements forward and report where the new range ends -- they don't (and can't) delete them because they can work on any arbitrary iterator range, not just a container.

j_random_hacker
  • 50,331
  • 10
  • 105
  • 169
6
// std::back_inserter usage ( std::inserter for map )
std::copy( source.begin(), source.end(), std::back_inserter( container ) );  

-

// mem_fun and bind usage (but boost better)
std::some_algorithm(..., std::mem_fun( func ) );  

not so useful, but powerful:

check is container sorted

std::adjacent_find( container.begin(), container.end(), greater<Container::value_type>() ) == container.end()

also examples mentioned by you and dirkgently.

bayda
  • 13,365
  • 8
  • 39
  • 48
2
copy(istreambuf_iterator<char>(cin), istreambuf_iterator<char>(),
     ostream_iterator<char>(cout));

Another oft used idiom is initializing a container from an array:

#include <map>
using namespace std;

int main() {
    typedef std::map<char,int> LUT;
    typedef LUT::value_type LUT_item_t;

    const LUT_item_t items[] = { LUT_item_t('b',1), 
                                 LUT_item_t('a',5) 
                               };

    LUT my_map(items, items + sizeof items/sizeof items[0]);
    return 0;
}

But if you want pure magic, look into Boost Lambda Library ;) A sample:

vector<int*> vp(10); 
sort(vp.begin(), vp.end(), *_1 > *_2);
dirkgently
  • 108,024
  • 16
  • 131
  • 187
  • Common mistake here. Because the istream_iterator uses the >> operator white space will be deleted. To compensate for this you should use the istreambuf_iterator to make sure you preserve white space. – Martin York Apr 10 '09 at 01:02
2

What I like most is to use bind1st/bind2nd/mem_fun in sort of delegates.

// will call a->func(v[i])
for_each(v.begin(), v.end(), bind1st(mem_fun(&A::func), &a));

// will call w[i]->func(72)
for_each(w.begin(), w.end(), bind2nd(mem_fun(&A::func), 72));

Using boost's bind and function are much better, but it is impressive which can be done with just STL.

Ismael
  • 2,995
  • 29
  • 45
  • 1
    I would probably select your post as an accepted answer now. It would be a little bit political though, because what I would like to show by this acceptation, is that boost::bind is overused in simple situations where STL is just sufficient. –  Jun 05 '09 at 14:51
  • Once you have boost::bind at your disposal, I don't see any need to go back to the original STL binders. They're too primitive. – StilesCrisis Dec 08 '11 at 17:08
1

For your second example use the value type:

#

Copy a map to a vector:

typedef map<T1, T2> MyMap;
MyMap myMap;
vector< MyMap::value_type > myVec(myMap.begin(), myMap.end());
Martin York
  • 257,169
  • 86
  • 333
  • 562
0

Using std::for_each in combination with a lambda function (since C++11)

std::vector<int> v(20);

std::for_each( v.begin(), v.end(), [] (int item)
{
    std::cout << item;
} );

instead of

for(std::vector<int>::const_iterator it = v.begin(); it != v.end(); ++it)
{
    std::cout << *it;
}

makes for better looking loops.

karlson
  • 5,325
  • 3
  • 30
  • 62
0

I like this one for looping over each line in a file. From a Andrew Koenig column in Dr. Dobbs.

for (string s; getline(stream,s); ) {
  // Process line
}
Jack Nock
  • 14,703
  • 5
  • 22
  • 18