Чтобы дать функциям опцию изменить вектор, я не могу сделать
curr = myvec.at( i );
doThis( curr );
doThat( curr );
doStuffWith( curr );
Но я должен сделать:
doThis( myvec.at( i ) );
doThat( myvec.at( i ) );
doStuffWith( myvec.at( i ) );
(как ответы моего другого вопроса, на который указывают)
Я собираюсь сделать партию ада вызовов к myvec.at()
затем. Как быстро это, по сравнению с первым примером с помощью переменной для хранения результата?
Существует ли другая опция для меня? Я могу так или иначе использовать указатели?
Когда это станет серьезным будут тысячи вызовов к myvec.at()
в секунду. Таким образом, каждая маленькая производительность едок важна.
Вы можете использовать ссылку:
int &curr = myvec.at(i);
// do stuff with curr
Функция-член at
выполняет проверку границ, чтобы убедиться, что аргумент находится в пределах размера вектор
. Профилирование - это единственный способ точно узнать, насколько он медленнее по сравнению с оператором []
. Использование ссылки здесь позволяет вам выполнить поиск один раз, а затем использовать результат в других местах. И вы можете сделать его ссылкой на- const
, если хотите защитить себя от случайного изменения значения.
Параметры, которые я вижу, примерно в обратном порядке предпочтения :
[]
вместо в ()
. в ()
один раз и сохраните его в качестве ссылки (см. Ответ Кристо выше). Честно говоря, вам следует поиграть с четырьмя различными подходами и просто использовать тот, который дает наиболее простой для понимания код. В большинстве случаев мы готовы пожертвовать несколькими машинными циклами ради кода, который легче поддерживать людям.
Из моих собственных тестов с аналогичным кодом (скомпилирован под gcc и Linux), оператор []
может быть заметно быстрее, чем на
, не из-за проверки границ, а из-за накладных расходов на обработку исключений. Замена на
(которая генерирует исключение при выходе за пределы) моей собственной проверкой границ, которая вызывала assert при выходе за пределы, дала ощутимое улучшение.
Использование ссылки, как Кристо сказал , позволяет вам только один раз понести накладные расходы на проверку границ.
Игнорирование проверки границ и накладных расходов на обработку исключений, оба оператора []
и в
должны быть оптимизированы для эквивалента прямого доступа к массиву или прямого доступа через указатель.
Однако, как сказал Крис Бек, альтернативы профилированию нет.
Векторы наиболее подходят для скорости доступа. Доступ к случайному элементу в векторе имеет сложность O (1) по сравнению с O (n) для общих связанных списков и O (log n) для деревьев ссылок.
Однако этот вопрос размещен неправильно, поскольку ответ на другой ваш вопрос сбил вас с пути, не объяснив, как исправить исходную проблему с помощью ссылки.
Оператор [] может быть быстрее, чем в
, потому что он не требует проверки границ.
Вы можете сделать curr
ссылкой, чтобы делать то, что вы хотите.
MyClass & curr = myvec.at(i);
Вы также можете провести сравнительный анализ, прежде чем беспокоиться. Современные процессоры довольно легко могут обрабатывать тысячи операций в секунду.
Причина, по которой первое не работает, заключается в том, что вы не устанавливаете указатель или итератор на адрес i-й переменной. Вместо этого вы устанавливаете curr равным значению i-й переменной, а затем изменяете curr. Я предполагаю, что doThis и doThat являются ссылками.
Сделайте это:
MyObject& curr = myvec.at( i );
Когда производительность является проблемой, нет замены профилированию. Возможности оптимизации компиляторов меняются от версии к версии, и крошечные незначительные изменения в исходном коде могут кардинально изменить итоговую производительность.
Никто не может ответить на этот вопрос, кроме вас самих: создайте тестовую систему, примените к ней несколько алгоритмов и посмотрите, что у вас получится.
пс. Если производительность действительно является проблемой, я получил увеличение скорости в 10 раз из декодера png, удалив векторы и заменив их необработанными массивами. Опять же, это было для Visual Studio 6. Я не утверждаю, что подстановка необработанного массива даст вам улучшение в 10 раз, но это то, что нужно попробовать.
Если это так, вы загружаете вектор, а затем обрабатываете его, не добавляя и не удаляя его больше элементов, затем рассмотрите возможность получения указателя на базовый массив и использования над ним операций с массивом, чтобы «избежать накладных расходов на вектор».
Если вы добавляете или удаляете элементы как часть своей обработки, то это небезопасно, поскольку базовый массив может быть перемещен в любую точку самим вектором.
Сложность at ()
постоянна, то есть на практике это означает, что он должен быть спроектирован так, чтобы не иметь соответствующей производительности. штраф.
Вы можете использовать []
, что также является постоянной сложностью, но не проверяет границы. Это было бы эквивалентно использованию арифметики с указателями и, таким образом, потенциально немного быстрее, чем первое.
В любом случае вектор специально разработан для постоянного доступа к любому из его элементов. Так что это должно быть наименьшей из ваших забот.