c ++ для использования временных переменных цикла

StackOverflow https://stackoverflow.com/questions/1042281

  •  22-07-2019
  •  | 
  •  

Вопрос

Что из перечисленного лучше и почему?(Особенно для c ++)

a.

int i(0), iMax(vec.length());//vec is a container, say std::vector
for(;i < iMax; ++i)
{
  //loop body
}

b.

for( int i(0);i < vec.length(); ++i)
{
  //loop body
}

Я видел рекомендации для (a) из-за вызова функции length.Это меня беспокоит.Разве ни один современный компилятор не выполняет оптимизацию (b), чтобы быть похожим на (a)?

Это было полезно?

Решение

Пример (b) имеет другое значение, чем пример (a), и компилятор должен интерпретировать его по мере написания.

Если (по какой-то выдуманной причине, которую я не могу придумать), я написал код для этого:

for( int i(0);i < vec.length(); ++i)
{
    if(i%4 == 0)
       vec.push_back(Widget());
}

Мне бы очень не хотелось, чтобы компилятор оптимизировал каждый вызов vec.length(), потому что я бы получил разные результаты.

Другие советы

Мне нравится:

for (int i = 0, e = vec.length(); i != e; ++i)

Конечно, это также будет работать для итераторов:

for (vector<int>::const_iterator i = v.begin(), e = v.end(); i != e; ++i)

Мне это нравится, потому что это эффективно (вызов end() только один раз), а также относительно кратким (нужно только набрать vector<int>::const_iterator один раз).

Я удивлен, что никто не сказал очевидного:

В 99,99% случаев это не имеет значения.

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

Здесь есть два вопроса для обсуждения:

  1. Область видимости переменной
  2. Переоценка конечного состояния

Область действия переменной

Обычно вам не нужно, чтобы переменная цикла была видна вне цикла.Вот почему вы можете объявить это внутри for построить.

Переоценка конечного состояния

Эндрю Шепард прекрасно выразил это:размещение вызова функции внутри конечного условия означает нечто иное:

for( vector<...>::size_type i = 0; i < v.size(); ++i ) { // vector size may grow.
   if( ... ) v.push_back( i ); // contrived, but possible
}

// note: this code may be replaced by a std::for_each construct, the previous can't.
for( vector<...>::size_type i = 0, elements = v.size(); i != elements; ++i ) {
}

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

Другой альтернативой может быть

for (vector<T>::iterator it=vec.begin();it!=vec.end();it++){
 //loop body
}

Если вам не нужна переменная цикла вне цикла, предпочтительнее второй подход.

Итераторы на самом деле дадут вам такую же хорошую или даже более высокую производительность.(Несколько лет назад была большая ветка сравнения на comp.lang.c ++.moderated).

Кроме того, я бы использовал

int i = 0;

Вместо синтаксиса, подобного конструктору, который вы используете.Хотя это и допустимо, но не является идиоматическим.

Как-то не связано:

Предупреждение:Сравнение знакового и беззнакового целого числа.

Правильный тип индексов массива и вектора: size_t.

Строго говоря, в C++ это даже std::vector<>::size_type.

Удивительно, сколько разработчиков C/C++ до сих пор ошибаются.

Посмотрим на сгенерированный код (я использую MSVS 2008 с полной оптимизацией).

а.

int i(0), iMax(vec.size());//vec is a container, say std::vector
for(;i < iMax; ++i)
{
  //loop body
}

Цикл for создает две ассемблерные инструкции.

б.

for( int i(0);i < vec.size(); ++i)
{
  //loop body
}

Цикл for создает 8 инструкций ассемблера.vec.size() успешно встроен.

в.

for (std::vector<int>::const_iterator i = vec.begin(), e = vec.end(); i != e; ++i)
{
  //loop body
}

Цикл for выдает 15 ассемблерных инструкций (все встроено, но в коде много переходов)

Итак, если ваше приложение критично к производительности, используйте a).В противном случае б) или в).

Следует отметить, что примеры итераторов:

for (vector<T>::iterator it=vec.begin();it!=vec.end();it++){
 //loop body
}

может сделать недействительным итератор цикла «it», если тело цикла приведет к перераспределению вектора.Таким образом, это не эквивалентно

for (int i=0;i<vec.size();++i){
 //loop body
}

где тело цикла добавляет элементы в vec.

Простой вопрос:ты меняешь? vec в петле?

ответ на этот вопрос приведет и к вашему ответу.

джрх

Компилятору очень сложно поднять vec.length() вызовите надежную уверенность в том, что он постоянен, если только он не будет встроен (что, надеюсь, часто так и происходит!).Но хотя бы i обязательно должен быть объявлен во втором стиле «b», даже если length вызов необходимо «вручную» вывести из цикла!

Этот предпочтительнее:

typedef vector<int> container; // not really required,
                               // you could just use vector<int> in for loop

for (container::const_iterator i = v.begin(); i != v.end(); ++i)
{
    // do something with (*i)
}
  • Я могу сразу сказать, что вектор не обновляется
  • каждый может сказать, что здесь происходит
  • Я знаю, сколько петель
  • v.end() Возвращает указатель один мимо последнего элемента, чтобы не было накладных расходов размера проверки
  • Легко обновить для разных контейнеров или типов значений

(б) не будет вычислять/вызывать функцию каждый раз.

-- начало отрывка ----

Движение инвариантного кода цикла:GCC включает движение инвариантного кода цикла как часть своего оптимизатора цикла, а также в проход частичного устранения избыточности.Эта оптимизация удаляет инструкции из циклов, которые вычисляют значение, которое не меняется на протяжении всего цикла.

--- конец отрывка --

Дополнительные оптимизации для gcc:

https://www.in.redhat.com/software/gnupro/technical/gnupro_gcc.php3

Почему бы не обойти этот вопрос полностью BOOST_FOREACH

#include <boost/foreach.hpp>

std::vector<double> vec;

//...

BOOST_FOREACH( double &d, vec)
{
    std::cout << d;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top