Создание объекта в цикле - PullRequest
4 голосов
/ 10 июня 2010
 std::vector<double> C(4);
 for(int i = 0; i < 1000;++i)
  for(int j = 0; j < 2000; ++j)
  {   
   C[0] = 1.0;
   C[1] = 1.0;
   C[2] = 1.0;
   C[3] = 1.0;
  }

на намного быстрее, чем

 for(int i = 0; i < 1000;++i)
  for(int j = 0; j < 2000; ++j)
  {
   std::vector<double> C(4);
   C[0] = 1.0;
   C[1] = 1.0;
   C[2] = 1.0;
   C[3] = 1.0;
  }

Я понимаю, что это происходит потому, что std::vector постоянно создается и создается в цикле, но у меня сложилось впечатление, что этобыло бы оптимизировано вне .

Является ли полностью неправильным держать переменные локальными в цикле всякий раз, когда это возможно?У меня было (возможно, ложное) впечатление, что это предоставит возможности оптимизации для компилятора.

Или, может быть, это относится только к типам POD, а не к чему-то вроде std::vector.

РЕДАКТИРОВАТЬ: Я использовал VC ++ 2005 (режим выпуска) с полной оптимизацией (/Ox) в Windows XP

Ответы [ 7 ]

3 голосов
/ 10 июня 2010

Совершенно неправильно держать локальные переменные в цикле, когда это возможно? У меня было (возможно, ложное) впечатление, что это предоставит возможности оптимизации для компилятора.

Нет, это хорошее эмпирическое правило. Но это только эмпирическое правило. Минимизация области видимости переменной дает компилятору больше свободы для распределения регистров и других оптимизаций, и, по крайней мере, что не менее важно, он обычно дает более читаемый код. Но это также зависит от того, является ли повторное создание / уничтожение дешевым или полностью оптимизированным. Это часто бывает ... Но не всегда.

Итак, как вы обнаружили, иногда это плохая идея.

2 голосов
/ 10 июня 2010

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

Это, вероятно, верно для встроенных типов, таких как int или double.

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

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

2 голосов
/ 10 июня 2010

Проблема в куче активности. Замените std::vector<double> C(4); на std::array<double, 4> C; и больше не должно иметь значения, где вы разместите переменную.

1 голос
/ 10 июня 2010

Создание vector является дорогостоящим, в этом случае, потому что он может выделить массив размера 4 в куче.

Если вы знаете размер локального вектора заранее, вы можететакже используйте автоматический массив :

for( int i = 0; i != 2000; ++i ) {
   int C[4]; // no initialization
   C[0] = 1;
   // ...
}

Таким образом, вы теряете стоимость выделения свободной памяти.

1 голос
/ 10 июня 2010

Второй способ - выделение новой памяти (в вашем случае 1000 * 2000 раз). Каждый из них - абсолютно новая область памяти в куче (хотя и не всегда новая, может находиться в одной и той же папке). Выделение памяти занимает больше времени, чем просто изменение значений, содержащихся в уже выделенной памяти.

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

0 голосов
/ 10 июня 2010

Первое, что вы должны сделать, это убедиться, что дизайн в порядке, это означает:

  • Легко ли понять код
  • Защищает ли код себя от ошибок
  • Является ли код легко расширяемым

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

Только если у вас есть реальныйпроблемы с производительностью, вы можете оптимизировать свой код (если компилятор еще не сделал этого для вас), например, поместив объявление переменной вне цикла.

0 голосов
/ 10 июня 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...