Вызов функции C ++ против новых блоков для Push / Popping в стеке - PullRequest
1 голос
/ 10 мая 2011

Я читал о области видимости переменных в C ++ и столкнулся с интересной структурой блоков:

int main(int argc, char **argv) {
    int local;

    { // New level of scope
        int more_local;
    }

    return 0;
}

Я понимаю, что переменные выталкиваются из стека в конце каждого блока, обозначенного закрывающей фигурной скобкой }.

Я также читал, что вызовы функций также помещают свои переменные в стек и завершаются в конце вызова, обозначенного закрывающей фигурной скобкой }:

void foo() {
    int more_local;
}

int main(int argc, char **argv) {
    int local;
    foo();

    return 0;
}

КакСтек обрабатывается по-разному в обеих ситуациях, и каковы преимущества и недостатки обоих?

Ответы [ 5 ]

4 голосов
/ 10 мая 2011

При вызове функции вы помещаете адрес возврата в стек и создаете новый кадр стека . Если вы просто заключаете части кода в фигурные скобки, вы определяете новую область действия, как вы сказали. Они похожи на любой блок кода, следующий за оператором управления, например if, for, while и т. Д.

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

2 голосов
/ 10 мая 2011

int more_local; будет помещено в стек в обоих случаях.Но во втором сценарии будут накладные расходы на вызов функции.

Я бы посоветовал вам подумать об этом:

void foo()
{
    int local;

    { // New level of scope
        int more_local_1;
    }
    { // New level of scope
        int more_local_2;
    }
}

Здесь more_local_1 и more_local_2 могут использовать одну и ту же область памяти,Когда-то он использовался для more_local_1 и во второй области видимости для more_local_2 переменной.

2 голосов
/ 10 мая 2011

Ну, вы могли бы сказать, что ваш первый пример можно рассматривать как встроенную функцию. : P
Но, как правило, вызовы функций и открытие нового scope не имеют никакого отношения друг к другу.
Когда вы вызываете функцию, адрес возврата и все аргументы помещаются в стек и извлекаются из нее после возврата из функции.
Открывая новый scope, вы просто вызываете деструктор всех объектов в этой области в конце его; отнюдь не гарантируется, что фактическое пространство, занимаемое этими переменными, сразу же выталкивается из стека. Это возможно, но пространство может также просто использоваться другими переменными в функции, в зависимости от прихотей компиляторов / оптимизаторов.

1 голос
/ 10 мая 2011
  • локальные области по-прежнему могут обращаться к другим локальным переменным, в то время как функциям необходимо явно передавать любую переменную вызывающего, которую им необходимо использовать

    • Передача переменных - это боль,но иногда это делает код более понятным, чтобы четко указывать меньший набор переменных, фактически необходимых для операций с областью видимости (а также поощряет группирование операций в дискретные функциональные блоки при наличии соответствующего имени функции и имен параметров, соответствующих контексту, и они 'затем он готов к повторному использованию)
  • вызовы функций вне строки имеют несколько других стековых пространств и издержек производительности: адреса возврата, сохраненные регистры, инструкции вызова и возврата

  • по сравнению с областью действия локальные области особенно хороши для минимизации области действия переменных, которые содержат важные ресурсы, такие как больший объем памяти, потоки, файловые дескрипторы и / или блокировки: более высокий уровеньи дольше работает функцияболее полезным может быть быстрое его очищение

    • сокращение времени жизни переменных также уменьшает число параллельных переменных, которые программист должен мысленно «отследить» для понимания и поддержки кода: чем меньше, тем лучше
  • иногда нет смысла выбирать произвольно разные идентификаторы, когда вы выполняете набор аналогичных операций, поэтому некоторые локальные области позволяют «перерабатывать» идентификатор«удобно

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

0 голосов
/ 14 июня 2015

Если вы наблюдаете код ассемблера для обеих программ, кажется, что нет никакой разницы, потому что компилятор, кажется, генерирует код ассемблера, чтобы выдвинуть новый кадр стека в текущий указатель стека, когда он встречает открывающую фигурную скобку или вызов функции и pop как только он встречает закрывающую фигурную скобку или оператор возврата. Преимущество во втором случае заключается в том, что вы можете вернуть значение с оператором возврата в функцию-вызывающую функцию. Но не в первом случае.

...