Odpowiedzi:
Wolałbym it - vec.begin()
dokładnie z przeciwnego powodu podanego przez Naveen: więc nie skompilowałby się, gdyby zmienić wektor na listę. Jeśli zrobisz to podczas każdej iteracji, możesz łatwo przekształcić algorytm O (n) w algorytm O (n ^ 2).
Inną opcją, jeśli nie przeskakujesz w kontenerze podczas iteracji, byłoby zachowanie indeksu jako drugiego licznika pętli.
Uwaga: it
Jest to wspólna nazwa dla iteratora pojemnika std::container_type::iterator it;
.
it
?
std::container_type::iterator it;
std::list
nie oferuje bezpośredniego dostępu do elementów według ich pozycji, więc jeśli nie możesz tego zrobić list[5]
, nie powinieneś być w stanie tego zrobić list.begin() + 5
.
Wolę, std::distance(vec.begin(), it)
ponieważ pozwoli mi to zmienić kontener bez żadnych zmian kodu. Na przykład, jeśli zdecydujesz się użyć std::list
zamiast tego, std::vector
który nie zapewnia iteratora o dostępie swobodnym, Twój kod nadal będzie się kompilował. Ponieważ std :: distance wybiera optymalną metodę w zależności od cech iteratora, nie zmniejszysz wydajności.
vec
to złe wieści. Jeśli kod zostałby ponownie napisany, aby był ogólny, biorąc pod uwagę typ kontenera jako parametr szablonu, wtedy możemy (i powinniśmy) mówić o obsłudze iteratorów bez dostępu losowego ;-)
vec
jest również złą wiadomością.
Jak pokazali UncleBens i Naveen, istnieją dobre powody dla obu. To, które z nich jest „lepsze”, zależy od tego, jakie zachowanie chcesz: czy chcesz zagwarantować zachowanie w czasie stałym, czy też chcesz, aby w razie potrzeby wrócił do czasu liniowego?
it - vec.begin()
zajmuje stały czas, ale operator -
jest definiowany tylko w iteratorach o swobodnym dostępie, więc kod nie kompiluje się na przykład z iteratorami list.
std::distance(vec.begin(), it)
działa dla wszystkich typów iteratorów, ale będzie działać tylko w trybie ciągłym, jeśli zostanie zastosowany w iteratorach o dostępie swobodnym.
Żadne z nich nie jest „lepsze”. Użyj tego, który robi to, czego potrzebujesz.
Podoba mi się ten:, it - vec.begin()
ponieważ dla mnie wyraźnie mówi „odległość od początku”. Dzięki iteratorom jesteśmy przyzwyczajeni do myślenia w kategoriach arytmetyki, więc -
znak jest tutaj najwyraźniejszym wskaźnikiem.
distance
?
it++
a nie coś takiego std::increment(it)
, prawda? Czy nie byłoby to również mniej jasne?
++
Operator jest zdefiniowany jako część sekwencji STL jak jak przyrost iteracyjnej. std::distance
oblicza liczbę elementów między pierwszym a ostatnim elementem. Fakt, że-
operator działa, jest jedynie zbiegiem okoliczności.
Jeśli jesteś już ograniczony / sztywno swój algorytm za pomocą std::vector::iterator
a std::vector::iterator
tylko, że nie ma znaczenia, która metoda będzie skończyć użyciu. Twój algorytm jest już skonkretyzowany poza punktem, w którym wybór jednego z nich może mieć znaczenie. Oboje robią dokładnie to samo. To tylko kwestia osobistych preferencji. Osobiście użyłbym wyraźnego odejmowania.
Jeśli natomiast chcesz zachować wyższy stopień ogólności w swoim algorytmie, a mianowicie, aby umożliwić możliwość zastosowania go w przyszłości w innym typie iteratora, najlepsza metoda zależy od twoich zamiarów . To zależy od tego, jak restrykcyjny chcesz być w odniesieniu do typu iteratora, którego możesz tutaj użyć.
Jeśli użyjesz jawnego odejmowania, twój algorytm będzie ograniczony do raczej wąskiej klasy iteratorów: iteratorów o swobodnym dostępie. (Z tego teraz otrzymujesz std::vector
)
Jeśli używasz distance
, twój algorytm będzie obsługiwał znacznie szerszą klasę iteratorów: iteratory wejściowe.
Oczywiście obliczanie distance
dla iteratorów bez dostępu losowego jest na ogół nieefektywną operacją (podczas gdy dla tych z dostępem losowym jest równie wydajne jak odejmowanie). To Ty decydujesz, czy Twój algorytm ma sens dla iteratorów bez dostępu losowego, pod względem wydajności. Jeśli wynikająca z tego utrata wydajności jest tak druzgocąca, że algorytm staje się całkowicie bezużyteczny, należy lepiej trzymać się odejmowania, tym samym zakazując nieefektywnych zastosowań i zmuszając użytkownika do poszukiwania alternatywnych rozwiązań dla innych typów iteratorów. Jeśli wydajność z iteratorami nieposiadającymi losowego dostępu jest nadal w użytecznym zakresie, powinieneś użyć distance
i udokumentować fakt, że algorytm działa lepiej z iteratorami o swobodnym dostępie.
Według http://www.cplusplus.com/reference/std/iterator/distance/ , ponieważ vec.begin()
jest to iterator o dostępie swobodnym , metoda odległości wykorzystuje -
operatora.
Odpowiedź jest więc taka sama z punktu widzenia wydajności, ale być może korzystanie z niej distance()
jest łatwiejsze do zrozumienia, jeśli ktoś będzie musiał przeczytać i zrozumieć Twój kod.
Użyłbym tego -
wariantu std::vector
tylko - jest całkiem jasne, co to znaczy, a prostota operacji (która nie jest niczym więcej niż odejmowaniem wskaźnika) jest wyrażona przez składnię ( distance
z drugiej strony brzmi jak pitagoras na pierwsze czytanie, prawda?). Jak wskazuje UncleBen, -
działa również jako twierdzenie statyczne na wypadek vector
przypadkowej zmiany na list
.
Myślę też, że jest to o wiele bardziej powszechne - nie ma jednak liczb, aby to udowodnić. Główny argument: it - vec.begin()
jest krótszy w kodzie źródłowym - mniej pracy na pisaniu, mniej miejsca. Ponieważ jasne jest, że właściwa odpowiedź na twoje pytanie sprowadza się do gustu, może to być również uzasadniony argument.
Oto przykład, aby znaleźć „wszystkie” wystąpienia 10 wraz z indeksem. Pomyślałem, że to pomoże.
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());
}