Производительность vector :: size (): это так же быстро, как чтение переменной? - PullRequest
26 голосов
/ 02 мая 2010

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

Ответы [ 7 ]

16 голосов
/ 02 мая 2010

Забавный вопрос.

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

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

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

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

Теперь, когда речь идет о возможной оптимизации, необходимо учитывать два момента:

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

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

11 голосов
/ 02 мая 2010

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

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

8 голосов
/ 02 мая 2010

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

Вероятно, нет.

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

Вероятно, нет.

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

5 голосов
/ 02 мая 2010

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

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

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

for (size_t i = 0, i_end = container.size(); i < i_end; ++i){
// do something performance critical
}
1 голос
/ 20 февраля 2013

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

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

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

0 голосов
/ 02 мая 2010

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

0 голосов
/ 02 мая 2010

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

...