C++11: Mit foreach über Smart Pointers iterieren
Problem:
In C++11 möchtest du über einen Smart Pointer (auto_ptr, shared_ptr, …) iterieren, z.B. über einen std::vector, mit der neuen for-Schleifen-Syntax.
Probieren wir es aus:
using namespace std;
shared_ptr<vector<int> > smartptr(/* A ptr to your vector */);
for(int s : smartptr) {
/* Etwas Nützliches tun */
}Beim Versuch, diesen Code zu kompilieren, gibt GCC die folgende Fehlermeldung aus (andere Zeilen werden der Einfachheit halber weggelassen)
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> >&)'oder, wenn LANG=de gesetzt ist:
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> >&)«Lösung 1 (empfohlen):
Dereferenziere einfach den Zeiger (das funktioniert, da operator* auf Smart Pointern definiert ist):
using namespace std;
shared_ptr<vector<int> > smartptr(/* A ptr to your vector */);
for(int s : *smartptr) {
/* Etwas Nützliches tun */
}Lösung 2:
Füge den folgenden Code irgendwo in deinem Quellcode vor der for-Schleife ein:
#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();
}Der obige Quellcode funktioniert nur für Shared Pointer, aber man kann einfach std::shared_ptr durch std::auto_ptr, std::weak_ptr oder einen beliebigen anderen Typ ersetzen, vorausgesetzt er kann mit * dereferenziert werden.
Diese Lösung erspart dir das Dereferenzieren des Zeigers, was je nach bevorzugtem Codestil gut oder schlecht sein kann. Je nach Compilereinstellungen können die zusätzlichen Symbole wegoptimiert werden oder nicht (das inline-Schlüsselwort ist nur eine Empfehlung und nicht verpflichtend für den Compiler), aber in den meisten Fällen erhält man wahrscheinlich genau die gleiche Geschwindigkeit wie bei Lösung 1.
Warum funktioniert das?
Der obige Quellcode funktioniert nur für Shared Pointer, aber man kann einfach std::shared_ptr durch std::auto_ptr, std::weak_ptr oder einen beliebigen anderen Typ ersetzen, vorausgesetzt er kann mit * dereferenziert werden.
Diese Lösung erspart dir das Dereferenzieren des Zeigers, was je nach bevorzugtem Codestil gut oder schlecht sein kann. Je nach Compilereinstellungen können die zusätzlichen Symbole wegoptimiert werden oder nicht (das inline-Schlüsselwort ist nur eine Empfehlung und nicht verpflichtend für den Compiler), aber in den meisten Fällen erhält man wahrscheinlich genau die gleiche Geschwindigkeit wie bei Lösung 1.
Lösung 3
Wenn du boost::foreach verwendest, könnte das für dich funktionieren, aber die Lösung ist ziemlich langsam, wenn der Compiler sie nicht wegoptimiert.
Sie basiert auf der Tatsache, dass boost::foreach ein Paar von Iteratoren akzeptieren kann.
BOOST_FOREACH(string str, foreach_wrap_ptr(mySharedPtr)) {
//...
}