"All memory allocated on the stack is known at compile time" 是什么意思?
What does it means "All memory allocated on the stack is known at compile time"?
阅读 this great tutorial 关于堆栈与堆的内容,我对这句话有疑问:堆栈上分配的所有内存在编译时都是已知的。
我的意思是,如果我处于取决于用户输入的 for
周期内(i
从 0 到 X),并且在 for
内我分配内存堆栈(例如创建一些 classes 的新实例并放入 class-容器中),它不知道编译程序时堆栈将如何增长(它错过了用户的输入) .
我是不是理解错了什么?
在考虑的情况下,STACK 表示编译器为您的方法中定义的局部变量分配的内存。 "You allocate"(在引号中,因为它是为你做的)定义变量时的这个内存:
void myMethod(int x)
{
int y;
for (y = 0; y < 10; y++)
{
int z = x + y;
}
}
本例中的所有x
、y
和z
都是在栈中分配的局部变量。
当您使用 new
运算符创建一些实例时,您在堆中分配内存(此处您分配不带引号),但要存储此分配内存的地址,您可能会使用在堆栈中分配的指针变量:
int * p = new int[10];
现在 p
是局部变量(存储在堆栈中),它存储在堆中为 10 个整数的数组分配的内存地址。
当编译器解析您的源代码时,它为调用您的方法制作了一组指令(就特定处理器而言),此时它计算所有局部变量所需的内存大小,并且在程序执行时内存将在方法开始之前(在方法完成后,所有内存将被释放,即堆栈将被释放在方法执行期间使用的数据 "will be lost").
I mean, if I'm within a for cycle that depends of user input (i from 0 to X), and within the for I allocate memory on the stack (such as create new instances of some classes and put inside a class-container), it can't know how will grow the stack when compile the program (it miss the input from user).
所以你有一个 class 容器...
std::vector< SomeClass > vec;
...在堆栈中。在一个循环中,您创建了一些 class...
的新实例
for ( size_t i = 0; i < X; ++i )
{
SomeClass x;
...在堆栈中。当你把它放入容器中时...
vec.push_back( x );
}
...该容器会将实例存储在堆上。
你只有 one SomeClass
在堆栈上,这个事实在编译时是已知的。堆栈不会超出那个实例。
尽管有 种方法可以在运行时增加堆栈(例如 alloca()
),因此本教程的一般性陈述并不完全正确。
reader 的陈述稍微简化了一点。你是对的,堆栈本质上是动态的,实际分配的数量可能因动态输入而异。这是一个带有递归函数的简单示例:
void f(int n)
{
int x = n * 10;
if(x == 0) return;
std::cout << x << std::endl;
f(n - 1);
}
int main()
{
int n;
std::cout << "Enter n: " << std::endl;
std::cin >> n;
f(n);
}
这里很明显f
的调用次数,一个递归函数,取决于用户输入的n
,所以对于任何给定的实例,编译器不可能知道确切的内存地址f
中的局部变量 x
。然而,它 确实 知道的是 x
相对于本地 堆栈框架 的偏移量,这就是我认为该示例所指的内容到。堆栈帧是每次函数调用发生时准备的堆栈局部区域。在给定的堆栈帧中,局部变量的位置实际上是相对于堆栈帧开头的已知常量偏移量。这个 'beginning' 在每次调用时都保存在一个标准寄存器中,因此编译器要找到任何本地地址所要做的就是将其固定的已知偏移量应用于这个动态 'base pointer'。
阅读 this great tutorial 关于堆栈与堆的内容,我对这句话有疑问:堆栈上分配的所有内存在编译时都是已知的。
我的意思是,如果我处于取决于用户输入的 for
周期内(i
从 0 到 X),并且在 for
内我分配内存堆栈(例如创建一些 classes 的新实例并放入 class-容器中),它不知道编译程序时堆栈将如何增长(它错过了用户的输入) .
我是不是理解错了什么?
在考虑的情况下,STACK 表示编译器为您的方法中定义的局部变量分配的内存。 "You allocate"(在引号中,因为它是为你做的)定义变量时的这个内存:
void myMethod(int x)
{
int y;
for (y = 0; y < 10; y++)
{
int z = x + y;
}
}
本例中的所有x
、y
和z
都是在栈中分配的局部变量。
当您使用 new
运算符创建一些实例时,您在堆中分配内存(此处您分配不带引号),但要存储此分配内存的地址,您可能会使用在堆栈中分配的指针变量:
int * p = new int[10];
现在 p
是局部变量(存储在堆栈中),它存储在堆中为 10 个整数的数组分配的内存地址。
当编译器解析您的源代码时,它为调用您的方法制作了一组指令(就特定处理器而言),此时它计算所有局部变量所需的内存大小,并且在程序执行时内存将在方法开始之前(在方法完成后,所有内存将被释放,即堆栈将被释放在方法执行期间使用的数据 "will be lost").
I mean, if I'm within a for cycle that depends of user input (i from 0 to X), and within the for I allocate memory on the stack (such as create new instances of some classes and put inside a class-container), it can't know how will grow the stack when compile the program (it miss the input from user).
所以你有一个 class 容器...
std::vector< SomeClass > vec;
...在堆栈中。在一个循环中,您创建了一些 class...
的新实例for ( size_t i = 0; i < X; ++i )
{
SomeClass x;
...在堆栈中。当你把它放入容器中时...
vec.push_back( x );
}
...该容器会将实例存储在堆上。
你只有 one SomeClass
在堆栈上,这个事实在编译时是已知的。堆栈不会超出那个实例。
尽管有 种方法可以在运行时增加堆栈(例如 alloca()
),因此本教程的一般性陈述并不完全正确。
reader 的陈述稍微简化了一点。你是对的,堆栈本质上是动态的,实际分配的数量可能因动态输入而异。这是一个带有递归函数的简单示例:
void f(int n)
{
int x = n * 10;
if(x == 0) return;
std::cout << x << std::endl;
f(n - 1);
}
int main()
{
int n;
std::cout << "Enter n: " << std::endl;
std::cin >> n;
f(n);
}
这里很明显f
的调用次数,一个递归函数,取决于用户输入的n
,所以对于任何给定的实例,编译器不可能知道确切的内存地址f
中的局部变量 x
。然而,它 确实 知道的是 x
相对于本地 堆栈框架 的偏移量,这就是我认为该示例所指的内容到。堆栈帧是每次函数调用发生时准备的堆栈局部区域。在给定的堆栈帧中,局部变量的位置实际上是相对于堆栈帧开头的已知常量偏移量。这个 'beginning' 在每次调用时都保存在一个标准寄存器中,因此编译器要找到任何本地地址所要做的就是将其固定的已知偏移量应用于这个动态 'base pointer'。