C++;函数调用与堆栈上推/弹出的新块 我在C++中阅读了变量范围,遇到了一个有趣的块结构: int main(int argc, char **argv) { int local; { // New level of scope int more_local; } return 0; }

C++;函数调用与堆栈上推/弹出的新块 我在C++中阅读了变量范围,遇到了一个有趣的块结构: int main(int argc, char **argv) { int local; { // New level of scope int more_local; } return 0; },c++,stack,block,function-calls,C++,Stack,Block,Function Calls,据我所知,变量是在每个块的末尾从堆栈中弹出的,该块由右大括号}表示 我还了解到,函数调用也会将其变量推送到堆栈上,并在调用结束时终止,该调用由右大括号表示}: void foo() { int more_local; } int main(int argc, char **argv) { int local; foo(); return 0; } 在这两种情况下,堆栈的处理方式如何不同?两者的优缺点是什么?您可以说,您的第一个示例可以看作是一个内联函数:P

据我所知,变量是在每个块的末尾从堆栈中弹出的,该块由右大括号
}
表示

我还了解到,函数调用也会将其变量推送到堆栈上,并在调用结束时终止,该调用由右大括号表示
}

void foo() {
    int more_local;
}

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

    return 0;
}

在这两种情况下,堆栈的处理方式如何不同?两者的优缺点是什么?

您可以说,您的第一个示例可以看作是一个内联函数:P
但一般来说,函数调用和打开一个新的
范围
彼此无关。
调用函数时,返回地址和所有参数将被推送到堆栈上,并在函数返回后从堆栈中弹出。

当打开一个新的
范围
时,只需在该范围的末尾调用该范围内所有对象的析构函数;并不能保证这些变量所占用的实际空间会立即从堆栈中弹出。它可以,但空间也可以被函数中的其他变量重用,这取决于编译器/优化器的突发奇想。

好吧,您可以说您的第一个示例可以看作是一个内联函数:P
但一般来说,函数调用和打开一个新的
范围
彼此无关。
调用函数时,返回地址和所有参数将被推送到堆栈上,并在函数返回后从堆栈中弹出。

当打开一个新的
范围
时,只需在该范围的末尾调用该范围内所有对象的析构函数;并不能保证这些变量所占用的实际空间会立即从堆栈中弹出。它可以,但空间也可以被函数中的其他变量重用,这取决于编译器/优化器的突发奇想。

通过函数调用,您将返回地址推送到堆栈上,并创建一个新的堆栈帧。如果您只是将代码的一部分用大括号括起来,那么正如您所说的,您正在定义一个新的范围。它们就像控制语句后面的任何代码块,例如if、for、while等


你不能在这里谈论优点和缺点,因为这是两件完全不同的事情。在很多情况下,用大括号括起代码块会让您受益匪浅,这会使代码更难阅读。

通过函数调用,您将返回地址推送到堆栈上,并创建一个新的堆栈框架。如果您只是将代码的一部分用大括号括起来,那么正如您所说的,您正在定义一个新的范围。它们就像控制语句后面的任何代码块,例如if、for、while等


你不能在这里谈论优点和缺点,因为这是两件完全不同的事情。在很多情况下,用大括号括起代码块会让您受益匪浅,这会使代码更难阅读。

int more\u local都将放置在堆栈上。但第二个场景将有函数调用的开销

我建议你考虑一下:

void foo()
{
    int local;

    { // New level of scope
        int more_local_1;
    }
    { // New level of scope
        int more_local_2;
    }
}
这里
more\u local\u 1
more\u local\u 2
可能共享相同的内存位置。曾经用过
more\u local\u 1
more\u local\u 2
变量的第二个范围。

int more\u local都将放置在堆栈上。但第二个场景将有函数调用的开销

我建议你考虑一下:

void foo()
{
    int local;

    { // New level of scope
        int more_local_1;
    }
    { // New level of scope
        int more_local_2;
    }
}
这里
more\u local\u 1
more\u local\u 2
可能共享相同的内存位置。曾经用过
more\u local\u 1
more\u local\u 2
变量的第二个范围。

  • 局部作用域仍然可以访问其他局部变量,而函数必须显式地传递它们需要使用的任何调用方变量

    • 传递变量是一件痛苦的事情,但有时它会使代码更容易理解,以便清楚地指出作用域操作实际需要的较小的变量集(同时鼓励将操作分组到离散的功能单元中,给定适当的函数名和上下文相关的参数名,然后它们就可以重用了)
  • 离线函数调用还有一些其他堆栈空间和性能开销:返回地址、保存的寄存器、调用和返回指令

  • 与函数作用域相比,局部作用域在最小化包含大量内存、线程、文件描述符和/或锁等重要资源的变量作用域方面尤其有效:函数的级别越高,运行时间越长,及时清理它就越有用

    • 缩短变量生存期还减少了程序员在理解和维护代码时必须在心里“跟踪”的并发变量数量:越少越好
  • 有时,在执行一组类似的操作时,必须选择任意不同的标识符没有多大意义,因此一些局部作用域允许方便地“回收”标识符

  • 局部作用域有点笨拙,占用了源代码中的“屏幕空间”,并且增加了缩进级别,因此在有特定的理由时使用它们,而不是在“任何时候都可以”的基础上使用它们是一个好主意

      • 局部作用域仍然可以访问其他局部变量,而函数必须显式地传递它们需要使用的任何调用方变量

        • 传递变量是一件痛苦的事情,但有时它会使代码更容易理解,从而清楚地指出作用域操作(以及encour)实际需要的较小的变量集