Antworten:
Ich würde es it - vec.begin()
genau aus dem entgegengesetzten Grund bevorzugen , den Naveen angegeben hat: Es würde also nicht kompiliert, wenn Sie den Vektor in eine Liste ändern. Wenn Sie dies während jeder Iteration tun, können Sie leicht einen O (n) -Algorithmus in einen O (n ^ 2) -Algorithmus verwandeln.
Eine andere Option, wenn Sie während der Iteration nicht im Container herumspringen, besteht darin, den Index als zweiten Schleifenzähler beizubehalten.
Hinweis: it
ist ein gebräuchlicher Name für einen Container-Iterator std::container_type::iterator it;
.
it
?
std::container_type::iterator it;
std::list
bietet keinen direkten Zugriff auf Elemente anhand ihrer Position. Wenn Sie dies nicht können list[5]
, sollten Sie dies nicht können list.begin() + 5
.
Ich würde es vorziehen, std::distance(vec.begin(), it)
da ich den Container ohne Codeänderungen ändern kann. Wenn Sie sich beispielsweise für die Verwendung entscheiden, std::list
anstatt std::vector
einen Iterator mit wahlfreiem Zugriff bereitzustellen, wird Ihr Code weiterhin kompiliert. Da std :: distance die optimale Methode in Abhängigkeit von den Iteratormerkmalen aufnimmt, treten auch keine Leistungseinbußen auf.
vec
ist eine schlechte Nachricht. Wenn der Code so umgeschrieben wurde, dass er generisch ist und den Containertyp als Vorlagenparameter verwendet, können (und sollten) wir über den Umgang mit Iteratoren mit nicht wahlfreiem Zugriff sprechen ;-)
vec
ist auch eine ziemlich schlechte Nachricht.
Wie UncleBens und Naveen gezeigt haben, gibt es für beide gute Gründe. Welches "besser" ist, hängt davon ab, welches Verhalten Sie möchten: Möchten Sie ein Verhalten mit konstanter Zeit garantieren oder möchten Sie, dass es bei Bedarf auf die lineare Zeit zurückgreift?
it - vec.begin()
nimmt konstante Zeit in operator -
Anspruch, ist jedoch nur für Iteratoren mit wahlfreiem Zugriff definiert, sodass der Code beispielsweise mit Listeniteratoren überhaupt nicht kompiliert wird.
std::distance(vec.begin(), it)
funktioniert für alle Iteratortypen, ist jedoch nur dann eine Operation mit konstanter Zeit, wenn sie für Iteratoren mit wahlfreiem Zugriff verwendet wird.
Keiner ist "besser". Verwenden Sie diejenige, die das tut, was Sie brauchen.
Ich mag dieses: it - vec.begin()
weil es mir klar sagt "Distanz vom Anfang". Bei Iteratoren sind wir es gewohnt, arithmetisch zu denken, daher ist das -
Vorzeichen hier der klarste Indikator.
distance
?
it++
und nicht so etwas std::increment(it)
, nicht wahr? Würde das nicht auch als weniger klar gelten?
++
Operator wird als Teil der STL-Sequenzen definiert, wie wir den Iterator inkrementieren. std::distance
berechnet die Anzahl der Elemente zwischen dem ersten und dem letzten Element. Die Tatsache, dass der -
Bediener arbeitet, ist nur ein Zufall.
Wenn Sie Ihren Algorithmus bereits auf die Verwendung von a std::vector::iterator
und std::vector::iterator
only beschränkt / fest codiert haben , spielt es keine Rolle, welche Methode Sie am Ende verwenden werden. Ihr Algorithmus ist bereits über den Punkt hinaus konkretisiert, an dem die Auswahl eines der beiden einen Unterschied machen kann. Beide machen genau das Gleiche. Es ist nur eine Frage der persönlichen Präferenz. Ich persönlich würde explizite Subtraktion verwenden.
Wenn Sie andererseits einen höheren Grad an Allgemeinheit in Ihrem Algorithmus beibehalten möchten, nämlich die Möglichkeit zuzulassen, dass er eines Tages auf einen anderen Iteratortyp angewendet wird, hängt die beste Methode von Ihrer Absicht ab . Dies hängt davon ab, wie restriktiv Sie in Bezug auf den hier verwendeten Iteratortyp sein möchten.
Wenn Sie die explizite Subtraktion verwenden, wird Ihr Algorithmus auf eine ziemlich enge Klasse von Iteratoren beschränkt: Iteratoren mit wahlfreiem Zugriff. (Das bekommen Sie jetzt von std::vector
)
Wenn Sie verwenden distance
, unterstützt Ihr Algorithmus eine viel breitere Klasse von Iteratoren: Eingabeiteratoren.
Natürlich ist die Berechnung distance
für Iteratoren mit nicht wahlfreiem Zugriff im Allgemeinen eine ineffiziente Operation (während sie für solche mit wahlfreiem Zugriff ebenso effizient ist wie die Subtraktion). Es liegt an Ihnen, zu entscheiden, ob Ihr Algorithmus für Iteratoren mit nicht wahlfreiem Zugriff in Bezug auf die Effizienz sinnvoll ist . Wenn der daraus resultierende Effizienzverlust so verheerend ist, dass Ihr Algorithmus völlig unbrauchbar wird, sollten Sie sich besser an die Subtraktion halten, um ineffiziente Verwendungen zu verhindern und den Benutzer zu zwingen, nach alternativen Lösungen für andere Iteratortypen zu suchen. Wenn die Effizienz mit Iteratoren ohne wahlfreien Zugriff immer noch im nutzbaren Bereich liegt, sollten Sie distance
die Tatsache verwenden und dokumentieren, dass der Algorithmus mit Iteratoren mit wahlfreiem Zugriff besser funktioniert.
Laut http://www.cplusplus.com/reference/std/iterator/distance/ verwendet die Distanzmethode den Operator , da vec.begin()
es sich um einen Iterator mit wahlfreiem Zugriff handelt-
.
Die Antwort ist also aus Sicht der Leistung dieselbe, aber vielleicht ist die Verwendung distance()
einfacher zu verstehen, wenn jemand Ihren Code lesen und verstehen müsste.
Ich würde die -
Variante std::vector
nur für verwenden - es ist ziemlich klar, was gemeint ist, und die Einfachheit der Operation (die nicht mehr als eine Zeigersubtraktion ist) wird durch die Syntax ausgedrückt ( distance
auf der anderen Seite klingt sie wie Pythonagoras auf der erste Lesung, nicht wahr?). Wie UncleBen hervorhebt, -
fungiert es auch als statische Behauptung, falls vector
versehentlich auf geändert wird list
.
Ich denke auch, dass es viel häufiger vorkommt - ich habe jedoch keine Zahlen, die dies beweisen. Hauptargument: it - vec.begin()
ist im Quellcode kürzer - weniger Schreibarbeit, weniger Platzbedarf. Da es klar ist, dass die richtige Antwort auf Ihre Frage Geschmackssache ist, kann dies auch ein gültiges Argument sein.
Hier ist ein Beispiel, um "alle" Vorkommen von 10 zusammen mit dem Index zu finden. Ich dachte, das wäre hilfreich.
void _find_all_test()
{
vector<int> ints;
int val;
while(cin >> val) ints.push_back(val);
vector<int>::iterator it;
it = ints.begin();
int count = ints.size();
do
{
it = find(it,ints.end(), 10);//assuming 10 as search element
cout << *it << " found at index " << count -(ints.end() - it) << endl;
}while(++it != ints.end());
}