2010-06-09 3 views
4
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.

EDIT: я использовал VC++ 2005 (режим выпуска) с полной оптимизацией (/Ox) на Windows XP

+1

Возможны побочные эффекты из-за создания объекта. Но, конечно, это контейнер STL, поэтому ваш компилятор может догадаться, что этого не произойдет. Кстати, вы скомпилировали правильные флаги оптимизации? – Pieter

+1

Какой компилятор, операционная система и параметры компилятора вы использовали? –

+0

@ Pieter & David: Обновлено – Jacob

ответ

3

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

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

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

+0

Спасибо jalf, я полагаю, это просто эмпирическое правило, и я не могу ожидать, что всемогущий компилятор будет сначала оптимизировать такие вещи, как 'std :: vector', без профилирования. – Jacob

+0

Некоторые компиляторы могут быть в состоянии сделать это в некоторых случаях. И, конечно же, во многих других случаях это не имеет значения с точки зрения производительности. Но не в этот раз. :) – jalf

0

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

1

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

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

1

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

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

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

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

0

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

  • ли код легко понять
  • Препятствует ли код себя от ошибок
  • ли код легко extensible

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

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

+0

Это * - реальная проблема с производительностью, так как я ее профилировал. – Jacob

+0

После этого вы можете поместить переменную за пределы цикла, но четко прокомментируйте свой код, почему вы это сделали, поэтому следующий разработчик не возвращает его в цикле. – Patrick

2

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

+1

Google говорит, что std :: array - это C++ 0x – Dummy00001

+0

, затем используйте boost или массив C-style. –

+0

Или 'std :: tr1 :: array', если у вас есть« наполовину современный »компилятор. – fredoverflow

2

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

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

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

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

Смежные вопросы