Расположены ли переменные внутри цикла (while или for) после завершения цикла?
Являются ли переменные, созданные внутри цикла while или for, удаленными из памяти после завершения выполнения цикла? кроме того, это плохая привычка кодирования-создавать временные переменные внутри цикла?
В этом примере он создает 100 переменных X и затем избавляется от них, или они удаляются на каждой итерации? спасибо.
Пример:
int cc =0;
while(cc < 100){
int X = 99; // <-- this variable
cc++;
}
8 ответов:
объем ипродолжительность жизни - это две разные вещи. Для переменных, определенных в блоке scope без
static, они более или менее тесно связаны, но они все еще различны-и вы можете выстрелить себе в ногу, если не будете держать их прямо.Цитирую фрагмент из вопроса:
int cc =0; while(cc < 100){ int X = 99; // <-- this variable cc++; }Область
X- это область текста программы, в которой видно ее имя. Он простирается от точки, в которой он определен, до конца. заключающего блока, который разделен символами{и}. (Тот факт, что блок является частью оператораwhile, не имеет прямого отношения к делу; сам блок определяет область действия.)Внутри блока имя
Xотносится к этой переменнойint. Вне блока имяXне видно.Время жизни
X- это время во время выполнения программы, КогдаXлогически существует. Он начинается, когда исполнение достигает открытие{(перед определением), и заканчивается, когда выполнение достигает закрытия}. Если блок выполняется 100 раз, тоXсоздается и" уничтожается " 100 раз, и имеет 100 несвязных жизней.Хотя имя
XОбъект , называемыйX, может быть доступен (прямо или косвенно) в любое время в пределах его жизненного цикла. Например, если мы передадим&Xфункции, то эта функция может прочитать и обновить объект, даже если функция полностью выходит за его рамки.Вы можете взять адрес
Xи сохранить этот адрес для использования после окончания его срока службы, но это приводит к неопределенному поведению. Указатель на объект, срок жизни которого закончился, является неопределенным, и любая попытка разыменовать его-или даже сослаться на значение указателя-имеет неопределенное поведение.На самом деле ничего особенного не должно происходить, когда объект достигает конца своего жизненный цикл. Язык просто требует, чтобы объект существовал в течение его жизни; вне этого все ставки отменяются. Пространство стека, выделенное для хранения объекта, может быть освобождено (что обычно просто означает перемещение указателя стека), или, в качестве оптимизации, пространство стека может оставаться выделенным и повторно использоваться для следующей итерации цикла.
Кроме того, это плохая привычка кодирования-создавать временные переменные внутри цикла?
Вовсе нет. До тех пор, пока вы не спасете адрес объекта после окончания его срока службы, с ним все в порядке. Выделение и освобождение очень часто выполняется при входе в функцию и выходе из нее, а не из блока, в целях оптимизации производительности. Ограничение переменных относительно узкой областью действия-очень хорошая привычка кодирования . Это облегчает понимание кода, ограничивая ненужные взаимодействия между различными частями кода. Если
Xопределено внутри тела цикла, то ничего внешний цикл может повлиять на него (если вы не сделали что-то слишком сложное), что облегчает рассуждение о коде.UPDATE: если
Xбыли типа с нетривиальным конструктором и / или деструктором, создание и уничтожениеXфактически должно выполняться при входе в блок и выходе из него (если компилятор не в состоянии оптимизировать этот код). Для объекта типаintэто не проблема.
Да, переменная создается и уничтожается N раз, если компилятор не оптимизирует ее каким-то образом (что он может, я полагаю). Это не очень большое дело, когда у вас есть только один
int. Это становится более проблематичным, когда у вас есть какой-то сложный объект, воссозданный 99 раз внутри вашего цикла.Небольшой практический пример:
#include <iostream> using namespace std; class TestClass { public: TestClass(); ~TestClass(); }; TestClass::TestClass() { cout<<"Created."<<endl; } TestClass::~TestClass() { cout<<"Destroyed"<<endl; } int main() { for (int i = 0; i < 5; ++i) { TestClass c; } return 0; }В этом коде
TestClass cбудет воссоздано 5 раз. IdeOne Demo .
Да. Любая переменная, определенная в области
{ }:if (true) { // Forgive me father for this heresy :) int a = 0; } a = 1; // This will throw an errorАвтоматически освобождается, как только он выходит за пределы области действия.
Это справедливо и в данном случае:
for (int i = 0; i < 10; ++i) { // Do stuff ... } i = 1; // This will throw an errorОбласть действия
iограничена циклом for, даже если он не был объявлен внутри пары{ }.
Как указывалось ранее, на самом деле нет необходимости создавать/уничтожать локальную переменную повторно.
Это ненужная трата процессорного времени.
Пример, скомпилированный с "gcc-S-masm=intel-fverbose-asm"
int crazyloop (int n) { if (n > 0) { int i; for (i = 0; i < n; i++) ; } return n; }Соответствующий список сборок выглядит следующим образом:
_Z9crazyloopi: .LFB0: .cfi_startproc push rbp # .cfi_def_cfa_offset 16 .cfi_offset 6, -16 mov rbp, rsp #, .cfi_def_cfa_register 6 mov DWORD PTR [rbp-20], edi # n, n cmp DWORD PTR [rbp-20], 0 # n, jle .L2 #, mov DWORD PTR [rbp-4], 0 # i, .L4: mov eax, DWORD PTR [rbp-4] # tmp89, i cmp eax, DWORD PTR [rbp-20] # tmp89, n jge .L2 #, add DWORD PTR [rbp-4], 1 # i, jmp .L4 # .L2: mov eax, DWORD PTR [rbp-20] # D.3136, n pop rbp # .cfi_def_cfa 7, 8 ret .cfi_endprocИнтересная часть заключается в ссылках на регистр RBP. После установки, это не меняет. Переменная " i " всегда находится на [rbp-4]. (Вариации кода, с большим количеством vars и т. д., дал те же результаты = нет никакого повторного выделения / освобождения = модификации верхней позиции стека).
Это самая разумная вещь: представьте себе цикл, который повторяется триллионы раз.Будет ли другой компилятор делать это по-другому? Возможно, да, но с какой стати ему это делать?
Безопасность может быть проблемой? Маловероятно; в этом случае программист должен просто перезаписать переменную, прежде чем позволить ей исчезнуть.
Да
Если вы хотите иметь доступ к переменной после цикла, вы должны объявить ее вне цикла
while(...) { int i = 0; i++; // valid } i++; // invalid, i doesnt exist in this context
iвне петлиint i = 0; while(...) { i++; // valid } i++; // validСрок службы виариабля ограничен контекстом
{...}, в котором он был создан Есть ли мы, где рассматривая объект, деструктор вызывался бы при достижении}
Да, они уничтожаются, когда выходят за пределы видимости. Обратите внимание, что это не относится к переменным в цикле. Это правило применяется ко всем переменным савтоматической длительностью хранения .
Любая переменная остается активной в пределах своей области видимости. За пределами области видимости эта конкретная переменная даже не выходит, забудьте о доступе к ее значению.
for(;;) { int var; // Scope of this variable is within this for loop only. } // Outside this for loop variable `var` doesn't exits.
Переменные, объявленные внутри, будут иметь свою собственную область видимости. вы можете использовать его, когда вы знаете, что вы не будете использовать эту переменную вне области действия. Это работа компилятора. :)
Comments