Есть ли накладные расходы на объявление переменной в цикле? (C ++) [дубликат]

Используйте этот код в Windows, если вы хотите отключить редактирование пользователя и разрешите Ctrl + C для копирования текста экрана:

def txtEvent(event):
    if(event.state==12 and event.keysym=='c' ):
        return
    else:
        return "break"

txt.bind("<Key>", lambda e: txtEvent(e))
147
задан 7 July 2010 в 21:21
поделиться

10 ответов

Stack space for local variables is usually allocated in function scope. So no stack pointer adjustment happens inside the loop, just assigning 4 to var. Therefore these two snippets have the same overhead.

190
ответ дан 23 November 2019 в 22:14
поделиться

Для примитивных типов и типов POD это не имеет значения. Компилятор выделит пространство стека для переменной в начале функции и освободит его, когда функция вернется в обоих случаях.

Для типов классов, не относящихся к POD, которые имеют нетривиальные конструкторы, это БУДЕТ иметь значение - в этом случае размещение переменной вне цикла вызовет конструктор и деструктор только один раз, а оператор присваивания - на каждой итерации, тогда как помещение его внутри цикла вызовет конструктор и деструктор для каждой итерации цикла. В зависимости от того, что делают конструктор, деструктор и оператор присваивания класса, это может быть или нежелательно.

98
ответ дан 23 November 2019 в 22:14
поделиться

They are both the same, and here's how you can find out, by looking at what the compiler does (even without optimisation set to high):

Look at what the compiler (gcc 4.0) does to your simple examples:

1.c:

main(){ int var; while(int i < 100) { var = 4; } }

gcc -S 1.c

1.s:

_main:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $24, %esp
    movl    $0, -16(%ebp)
    jmp L2
L3:
    movl    $4, -12(%ebp)
L2:
    cmpl    $99, -16(%ebp)
    jle L3
    leave
    ret

2.c

main() { while(int i < 100) { int var = 4; } }

gcc -S 2.c

2.s:

_main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $24, %esp
        movl    $0, -16(%ebp)
        jmp     L2
L3:
        movl    $4, -12(%ebp)
L2:
        cmpl    $99, -16(%ebp)
        jle     L3
        leave
        ret

From these, you can see two things: firstly, the code is the same in both.

Secondly, the storage for var is allocated outside the loop:

         subl    $24, %esp

And finally the only thing in the loop is the assignment and condition check:

L3:
        movl    $4, -12(%ebp)
L2:
        cmpl    $99, -16(%ebp)
        jle     L3

Which is about as efficient as you can be without removing the loop entirely.

67
ответ дан 23 November 2019 в 22:14
поделиться

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

РЕДАКТИРОВАТЬ: Этот ответ в настоящее время в основном устарел. С появлением постклассических компиляторов случаи, когда компилятор не может это понять, становятся редкими. Я все еще могу их построить, но большинство людей классифицируют конструкцию как плохой код.

12
ответ дан 23 November 2019 в 22:14
поделиться

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

10
ответ дан 23 November 2019 в 22:14
поделиться

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

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

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

Предположим, у вас есть класс LockMgr , который получает критическую секцию при создании и выпуске при уничтожении:

while (i< 100) {
    LockMgr lock( myCriticalSection); // acquires a critical section at start of
                                      //    each loop iteration

    // do stuff...

}   // critical section is released at end of each loop iteration

сильно отличается от:

LockMgr lock( myCriticalSection);
while (i< 100) {

    // do stuff...

}
8
ответ дан 23 November 2019 в 22:14
поделиться

Оба контура имеют одинаковую эффективность. Оба они займут бесконечное количество времени :) Возможно, стоит увеличить i внутри циклов.

6
ответ дан 23 November 2019 в 22:14
поделиться

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

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

0
ответ дан 23 November 2019 в 22:14
поделиться

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

-1
ответ дан 23 November 2019 в 22:14
поделиться

это неправда есть накладные расходы, однако их игнорируемые накладные расходы.

Даже если они, вероятно, окажутся в одном и том же месте в стеке, он все равно присваивает их. Он назначит ячейку памяти в стеке для этого int, а затем освободит ее в конце}. Не в смысле без кучи, в смысле, он переместит sp (указатель стека) на 1. И в вашем случае, учитывая, что у него есть только одна локальная переменная, он просто будет приравнивать fp (указатель кадра) и sp

Короткий ответ будет: НЕ ЗАНИМАЙТЕСЬ, ЛЮБОЙ СПОСОБ РАБОТАЕТ ПОЧТИ ЖЕ.

Но попробуйте прочитать больше о том, как стек организовано. В моей старшей школе читались неплохие лекции по этому поводу. Если вы хотите узнать больше, проверьте здесь http://www.cs.utk.edu/~plank/plank/classes/cs360/360/notes/Assembler1/lecture.html

-6
ответ дан 23 November 2019 в 22:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: