Подтвердить что ты не робот

Производительность vector:: size(): это так же быстро, как чтение переменной?

Я делаю обширный расчет по большому вектору целых чисел. При вычислении размер вектора не изменяется. Код кода часто получает размер вектора. Что быстрее в общем случае: используя функцию vector::size() или используя вспомогательную константу vectorSize, сохраняющую размер вектора? Я знаю, что компиляторы обычно могут встроить функцию size() при настройке правильных флагов компилятора, однако создание функции inline - это то, что может сделать компилятор, но не может быть принудительно.

4b9b3361

Ответ 1

Смешной вопрос.

Итак, что произойдет? Хорошо, если вы отлаживаете с помощью gdb, вы увидите что-то вроде трех переменных-членов (имена не точны):

  • _M_begin: указатель на первый элемент динамического массива
  • _M_end: указатель один за последним элементом динамического массива
  • _M_capacity: указатель за последним элементом, который может быть сохранен в динамическом массиве

Таким образом, реализация vector<T,Alloc>::size() обычно сводится к:

return _M_end - _M_begin;  // Note: _Mylast - _Myfirst in VC 2008

Теперь при рассмотрении возможных оптимизаций есть две вещи:

  • будет ли эта функция встроена? Вероятно: я не писатель-компилятор, но это хорошая ставка, поскольку накладные расходы на вызов функции будут затушевывать фактическое время здесь, и поскольку это шаблонный, у нас есть весь код, доступный в блоке перевода
  • будет получен кешированный результат (т.е. вид неименованной локальной переменной): это вполне может быть, но вы не узнаете, если не разобрали сгенерированный код

Другими словами:

  • Если вы храните size самостоятельно, есть хороший шанс, что он будет так же быстро, как компилятор сможет его получить...
  • но вы подвергаете себя аварийному завершению: что если вы вдруг измените вектор и не обновляете переменную;)?

Во всяком случае, я серьезно сомневаюсь, что это стоит хлопот. Это микро-оптимизация в лучшем случае и вряд ли даст большую часть улучшения.

Ответ 2

Как я понимаю в спецификации С++ 1998 года, vector<T>::size() занимает постоянное время, а не линейное время. Таким образом, этот вопрос, вероятно, сводится к тому, быстрее ли читать локальную переменную, чем вызвать функцию, которая очень мало работает.

Поэтому я утверждаю, что сохранение вашего вектора size() в локальной переменной ускорит вашу программу на небольшое количество, так как вы будете называть только эту функцию (и, следовательно, небольшая константа количество времени, которое требуется выполнить) один раз, а не много раз.

Ответ 3

Производительность vector:: size(): это так же быстро, как чтение переменной?

Возможно, нет.

Имеет ли значение

Возможно, нет.

Если работа, которую вы делаете за итерацию, крошечная (например, одна или две целые операции), служебные данные будут незначительными.

Ответ 4

В каждой реализации я видел, что vector::size() выполняет вычитание end() и begin(), т.е. не так быстро, как чтение переменной.

При реализации вектора разработчик должен сделать выбор между тем, который должен быть самым быстрым, end() или size(),, т.е. хранить количество инициализированных элементов или указатель/итератор для элемента после последнего инициализированного элемента. Другими словами; итерации с помощью итераторов.

Если вы беспокоитесь о производительности size(), напишите свой индекс, основанный на цикле, как это:

for (size_t i = 0, i_end = container.size(); i < i_end; ++i){
// do something performance critical
}

Ответ 5

Я всегда сохраняю vector.size() в локальной переменной (только если vector.size() не изменяется в цикле for!).
Зачем? Потому что вызов его на каждой итерации и сохранение его в локальной переменной происходит намного быстрее. Это то, что я испытал в своих приложениях.
Я не могу дать вам никаких реальных чисел, но это имело заметную разницу.

И всем тем, кто жалуется на микро-оптимизацию:
Когда вы пишете огромный цикл for, вы просто (просто для удовольствия) вставляете ненужное вычитание в нем? Нет, вы этого не делаете.

Почему бы вам просто не профилировать его? Огромный вектор и std:: time будут прекрасно работать.

Ответ 6

Вы можете написать себе функтор для своего тела цикла и вызвать его через std::for_each. Он выполняет итерацию для вас, а затем ваш вопрос становится спорным. Тем не менее, вы вводите вызов функции (который может или не может быть встроен) для каждой итерации цикла, поэтому вам лучше всего профилировать его, если вы не получите ожидаемую производительность.

Ответ 7

Всегда просматривайте профиль своего приложения, прежде чем искать такую ​​микро-оптимизацию. Помните, что даже если он выполняет вычитание, компилятор может все же легко оптимизировать его во многих отношениях, что отрицательно повлияет на потерю производительности.