| Home | Libraries | People | FAQ | More

## Pitfalls

This section describes some common pitfalls with `BOOST_FOREACH`.

### Types With Commas

Since `BOOST_FOREACH` is a macro, it must have exactly two arguments, with exactly one comma separating them. That's not always convenient, especially when the type of the loop variable is a template. Consider trying to iterate over a `std::map`:

    std::map<int,int> m;

    // ERROR! Too many arguments to BOOST_FOREACH macro.
    BOOST_FOREACH(std::pair<int,int> p, m) // ...

One way to fix this is with a typedef.

    std::map<int,int> m;
    typedef std::pair<int,int> pair_t;

    BOOST_FOREACH(pair_t p, m) // ...

Another way to fix it is to predeclare the loop variable:

    std::map<int,int> m;
    std::pair<int,int> p;

    BOOST_FOREACH(p, m) // ...

### Hoisting and Iterator Invalidation

Under the covers, `BOOST_FOREACH` uses iterators to traverse the element sequence. Before the loop is executed, the end iterator is cached in a local variable. This is called hoisting, and it is an important optimization. It assumes, however, that the end iterator of the sequence is stable. It usually is, but if we modify the sequence by adding or removing elements while we are iterating over it, we may end up hoisting ourselves on our own petard.

Consider the following code:

    std::vector<int> vect(4, 4);
    BOOST_FOREACH(int i, vect)
    {
        vect.push_back(i + 1);
    }

This code will compile, but it has undefined behavior. That is because it is logically equivalent to the following:

    std::vector<int> vect(4, 4);
    for(std::vector<int>::iterator it1 = vect.begin(), it2 = vect.end();
        it1 != it2; ++it1)
    {
        int i = *it1;
        vect.push_back(i + 1); // Oops! This invalidates it1 and it2!
    }

The call to `vect.push_back()` will cause all iterators into `vect` to become invalid, including `it1` and `it2`. The next iteration through the loop will cause the invalid iterators to be used. That's bad news.

The moral of the story is to think twice before adding and removing elements from the sequence over which you are iterating. If doing so could cause iterators to become invalid, don't do it. Use a regular `for` loop instead.