C++11 : Iterate over smart pointers using foreach loop

Problem:

In C++11 you want to iterate over a smart pointer (auto_ptr, shared_ptr, …). collection, say a std::vector, using the new for loop syntax.

Let’s try it out:

using namespace std;
shared_ptr<vector<int> > smartptr(/* A ptr to your vector */);
for(int s : smartptr) {
    /* do something useful */
}

When trying to compile this code, GCC emits the following error message (other lines are omitted for the sake of simplicity)

error: no matching function for call to 'begin(std::shared_ptr<std::vector<int> >&)'
error: no matching function for call to 'end(std::shared_ptr<std::vector<int> >&)'

or, when LANG=de is set:

Fehler: keine passende Funktion für Aufruf von »begin(std::shared_ptr<std::vector<int> >&)«
Fehler: keine passende Funktion für Aufruf von »end(std::shared_ptr<std::vector<int> >&)«

Solution 1 (recommended):

Simply dereference the pointer (this works as operator* is defined on smart pointers):

using namespace std;
shared_ptr<vector<int> > smartptr(/* A ptr to your vector */);
for(int s : *smartptr) {
    /* do something useful */
}

Solution 2:

Include the following code somewhere in your source code before the for loop:

#include <memory>
template<typename T>
auto inline begin(std::shared_ptr<T> ptr) -> typename T::iterator {
    return ptr->begin();
}

template<typename T>
auto inline end(std::shared_ptr<T> ptr) -> typename T::iterator {
    return ptr->end();
}

The source code above works for shared pointers only, but you can simply exchange std::shared_ptr by std::auto_ptr, std::weak_ptr or whatever type you’d like, assuming it can be dereferenced using *.

This solution saves you from dereferencing the pointer, which might be good or bad depending on your preferred coding style. Depending on your compiler settings, the extra symbols might be optimized out or not (the inline keyword is only a recommendation and not mandatory for the compiler), but in most cases, you probably end up with exactly the same speed as when using solution 1.

Why does this work?

The source code above works for shared pointers only, but you can simply exchange std::shared_ptr by std::auto_ptr, std::weak_ptr or whatever type you’d like, assuming it can be dereferenced using *.

This solution saves you from dereferencing the pointer, which might be good or bad depending on your preferred coding style. Depending on your compiler settings, the extra symbols might be optimized out or not (the inline keyword is only a recommendation and not mandatory for the compiler), but in most cases, you probably end up with exactly the same speed as when using solution 1.

Solution 3

If you are using boost::foreach, this might work for you, but the solution is pretty slow if the compiler doesn’t optimize it out.

It’s based on the fact that boost::foreach can take a pair of iterators.

BOOST_FOREACH(string str, foreach_wrap_ptr(mySharedPtr)) {
    //...
}