Відповіді:
Я вважаю it - vec.begin()
за краще саме з протилежної причини, яку подав Naveen: тому він не складеться, якщо ви переймете вектор у список. Якщо ви робите це під час кожної ітерації, ви можете легко перетворити алгоритм O (n) в алгоритм O (n ^ 2).
Інший варіант, якщо ви не стрибаєте в контейнері під час ітерації, - це зберігати індекс як лічильник другого циклу.
Примітка: it
це загальна назва для контейнера ітератора std::container_type::iterator it;
.
it
?
std::container_type::iterator it;
std::list
що не надає прямий доступ до елементів за їхньою позицією, тому, якщо ви не можете цього зробити list[5]
, ви не зможете це зробити list.begin() + 5
.
Я вважаю за краще, std::distance(vec.begin(), it)
оскільки це дозволить мені змінити контейнер без будь-яких змін коду. Наприклад, якщо ви вирішили використовувати std::list
замість std::vector
якого не передбачений ітератор випадкового доступу, ваш код все одно буде компілюватися. Оскільки std :: distance підбирає оптимальний метод залежно від рис ітератора, ви також не будете погіршувати продуктивність.
vec
- це погані новини. Якщо код був переписаний на загальний характер, приймаючи тип контейнера як параметр шаблону, тоді ми можемо (і повинні) говорити про обробку ітераторів без випадкового доступу ;-)
vec
теж погана новина.
Як показали UncleBens та Naveen, для обох є вагомі причини. Який з них "кращий" залежить від того, яку поведінку ви хочете: Ви хочете гарантувати поведінку постійного часу, чи ви хочете, щоб вона повернулася до лінійного часу, коли це необхідно?
it - vec.begin()
займає постійний час, але operator -
визначається лише на ітераторах випадкового доступу, тому код взагалі не компілюється із ітераторами списку.
std::distance(vec.begin(), it)
працює для всіх типів ітераторів, але буде операцією постійного часу лише у разі використання ітераторів випадкового доступу.
Ні один не "кращий". Використовуйте той, що робить те, що вам потрібно.
Мені це подобається: it - vec.begin()
адже мені чітко сказано "відстань від початку". З ітераторами ми звикли думати з точки зору арифметики, тому -
знак є найяснішим показником тут.
distance
?
it++
а не щось на кшталт std::increment(it)
, чи не так? Чи не вважатиметься це менш зрозумілим?
++
Оператор визначається як частина STL послідовностей , як , як ми збільшуємо итератор. std::distance
обчислює кількість елементів між першим і останнім елементом. Те, що -
оператор працює - це лише збіг обставин.
Якщо ви вже обмежили / жорстко закодували свій алгоритм на використання єдиного std::vector::iterator
і std::vector::iterator
єдиного, це не має значення, який метод ви в кінцевому підсумку будете використовувати. Ваш алгоритм вже конкретизований поза межами тієї точки, коли вибір одного з інших може змінити будь-яке значення. Вони обидва роблять точно те саме. Це лише питання особистої переваги. Я особисто використовував би чітке віднімання.
Якщо, з іншого боку, ви хочете зберегти більш високий ступінь загальності у своєму алгоритмі, а саме, щоб дозволити можливість того, що якийсь день у майбутньому він може бути застосований до якогось іншого типу ітератора, то найкращий метод залежить від вашого наміру . Це залежить від того, наскільки ви хочете бути обмеженими щодо типу ітератора, який можна тут використовувати.
Якщо ви використовуєте явне віднімання, ваш алгоритм буде обмежений досить вузьким класом ітераторів: ітераторів з випадковим доступом. (Це те, що ви отримуєте зараз від std::vector
)
Якщо ви використовуєте distance
, ваш алгоритм буде підтримувати набагато ширший клас ітераторів: ітератори введення.
Звичайно, обчислення distance
для ітераторів без випадкового доступу, як правило, є неефективною операцією (в той час, як, для випадкового доступу, це так само ефективно, як і віднімання). Ви вирішуєте, чи має ваш алгоритм сенс для ітераторів без випадкового доступу, залежно від ефективності. Тому що втрата ефективності нищівна до того, що робить ваш алгоритм абсолютно марним, тоді вам слід краще дотримуватися віднімання, забороняючи таким чином неефективне використання і змушуючи користувача шукати альтернативні рішення для інших типів ітераторів. Якщо ефективність роботи з ітераторами без випадкового доступу все ще знаходиться в застосуваному діапазоні, то слід використовувати distance
та документувати той факт, що алгоритм краще працює з ітераторами випадкового доступу.
Відповідно до http://www.cplusplus.com/reference/std/iterator/distance/ , оскільки vec.begin()
це ітератор випадкового доступу , метод дистанції використовує -
оператор.
Тож відповідь з точки зору продуктивності - однакова, але, можливо, використання distance()
легше зрозуміти, чи комусь доведеться читати та розуміти ваш код.
Я б застосував -
варіант std::vector
лише для цього - досить зрозуміло, що мається на увазі, а простота операції (яка не більше ніж віднімання вказівника) виражається синтаксисом ( distance
з іншого боку, це звучить як піфагор на перше читання, чи не так?). Як вказує UncleBen, він -
також виступає як статичне твердження у випадку, якщо воно vector
буде офіційно змінено list
.
Крім того, я думаю, що це набагато частіше - все ж немає цифр, щоб довести це. Головний аргумент: it - vec.begin()
коротший вихідний код - менше набору тексту, менше зайнятого місця. Оскільки зрозуміло, що правильна відповідь на ваше запитання зводиться до смаку, це також може бути вагомим аргументом.
Ось приклад для пошуку "всіх" подій 10 разом з індексом. Думав, що це допоможе.
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());
}