Теоретически это не указано, но на практике не происходит выделения для отдельных объектов базового типа, таких как int, double, T * и т. Д. В некоторых случаях указатель стека не изменяется, и компилятор просто повторно использует место для других переменных:
for (int i=0 ; i < 10 ; i++)
foo(i);
for (int j=0 ; j < 10 ; j++)
foo(j);
Скорее всего, компилятор будет использовать пространство i
для выделения j
. Это легко проверить на godbolt.org с помощью gcc :
.L2:
mov edi, ebx
add ebx, 1
call foo(int)
cmp ebx, 10
jne .L2
xor ebx, ebx
.L3:
mov edi, ebx
add ebx, 1
call foo(int)
cmp ebx, 10
jne .L3
Мало того, что циклы идентичны, они даже не используют стек. Вместо стека переменные i
и j
размещаются в `ebx. В этом примере распределение и освобождение полностью прозрачны и являются простым использованием или отсутствием использования регистров.
Более сложный пример будет делать то же самое в стеке:
int foo(int);
void bar(int*);
void bar()
{
{
int a[10];
for (int i=0 ; i < 10 ; i++)
a[i] = foo(i);
bar(a);
}
{
int b[10];
for (int j=0 ; j < 10 ; j++)
b[j] = foo(j);
bar(b);
}
}
Кроме того, консультируясь Второй пример Godbolt.org производит:
xor ebx, ebx ; <--- this is simply part of the next block
sub rsp, 48; <--- allocating the stack space
.L2:
mov edi, ebx
call foo(int)
mov DWORD PTR [rsp+rbx*4], eax
add rbx, 1
cmp rbx, 10
jne .L2
mov rdi, rsp
xor ebx, ebx ; <--- this is simply part of the next block
call bar(int*)
.L3:
mov edi, ebx
call foo(int)
mov DWORD PTR [rsp+rbx*4], eax
add rbx, 1
cmp rbx, 10
jne .L3
mov rdi, rsp
call bar(int*)
add rsp, 48 ; <-- deallocating the stack space
Здесь также код идентичен для двух случаев. В стеке нет освобождения или распределения переменных. Линия:
a[i] = foo(i);
переводится на
mov DWORD PTR [rsp+rbx*4], eax
, который просто записывает данные относительно указателя стека (rsp
). Он в основном находит содержимое a
в соответствии с его положением относительно указателя стека. Указатель стека не обновляется между двумя блоками кода, он только передается в bar()
путем копирования указателя стека в rdi
:
mov rdi, rsp
call bar(int*)
Как я показал, обычно во время работы блока не происходит выделения и освобождения. Как правило, в начале и конце функции указатель стека обновляется для отражения переменных.
В отличие от простых целочисленных значений, типы с деструкторами более сложны, но я не буду вдаваться в подробности, потому что это не было задано в вопросе.