C++ 对C+动态内存分配的确切含义有点困惑+;

C++ 对C+动态内存分配的确切含义有点困惑+;,c++,memory,memory-management,stack,C++,Memory,Memory Management,Stack,关于动态的确切含义,我听到过一些相互矛盾的事情,就这一点而言,是自动的,内存分配。我听说堆栈被称为自动内存分配和动态内存分配。我可以看到这两种情况,因为堆栈内存块大小是在程序执行之前确定的,所以它的最大大小在运行时不能增长。然而,在程序执行期间,随着函数数据被推送到堆栈上或从堆栈上弹出,堆栈会不断增长和收缩 从这个意义上说,这不是动态内存分配吗 如果是这样的话,那么仅仅将堆称为动态堆不是很混乱吗 有人能帮我澄清一下吗 编辑:在撰写本文时,我似乎混淆了一些我不知道的概念。在C++中,堆栈的低级字节

关于动态的确切含义,我听到过一些相互矛盾的事情,就这一点而言,是自动的,内存分配。我听说堆栈被称为自动内存分配和动态内存分配。我可以看到这两种情况,因为堆栈内存块大小是在程序执行之前确定的,所以它的最大大小在运行时不能增长。然而,在程序执行期间,随着函数数据被推送到堆栈上或从堆栈上弹出,堆栈会不断增长和收缩

从这个意义上说,这不是动态内存分配吗

如果是这样的话,那么仅仅将堆称为动态堆不是很混乱吗

有人能帮我澄清一下吗

编辑:在撰写本文时,我似乎混淆了一些我不知道的概念。在C++中,堆栈的低级字节集和堆内存管理和相同的事物的高级概念之间有区别。关于这一点的澄清,请参考我下面接受的答案。

根据:

动态内存分配是指执行手动内存分配 管理层

从这个意义上讲,堆栈不是动态的,因为在编译时必须知道堆栈变量的大小:

C编程语言静态地管理内存,自动地管理内存, 或者动态地静态持续时间变量在主 内存,通常与程序的可执行代码一起,以及 在程序的生命周期内保持自动持续时间变量 在堆栈上分配,并在调用函数和 返回。对于静态持续时间和自动持续时间变量,大小 分配的类型必须是编译时常量。[…]分配内存的生存期也会引起关注。[…]通过使用动态内存分配可以避免这些限制

实际上,即使在堆栈上,也可以通过以下几种方式动态分配内存:

  • 使用
    alloca()
    函数
  • 使用C中自C99标准以来可用的可变长度数组或作为GCC扩展
  • 使用C++实验<代码> DyNoxs/Cuth>容器.< /LI> 但是,堆栈内存的这些使用并不典型,而且可能更重要的是,这样做仍然不能在对象的生命周期方面提供额外的灵活性


    你的第二个困惑是关于堆栈的增长。是的,堆栈的最大大小是静态确定的。但是,最大大小远大于正常程序所需的大小(Linux上默认为8MB),甚至可以在运行时通过使用操作系统API(Linux上的
    setrlimit
    )更改该数字。在程序执行期间,堆栈的实际大小会动态地增长和收缩,直到达到此限制。

    我将尽可能地消除混淆。首先,学习将低级内存模型概念(堆栈、堆)与c++级内存概念分开。在C++世界中,<代码>堆栈和 HEAP不意味着任何类似于低级模型中堆栈或堆的任何东西。p> 低电平存储器模型 首先,让我们讨论一下低级内存模型。传统上,内存分为“堆栈”内存和“堆”内存,我将在下面介绍

    堆栈 堆栈由所谓的“堆栈指针”CPU寄存器管理,该寄存器始终指示堆栈的顶部,并从高级内存地址连续转到低级内存地址。由于寄存器始终指向堆栈顶部,因此不需要任何与堆栈相关的实际内存管理—当您需要更多内存时,只需减少指针中存储的值—这就是您的内存,它被认为是为您分配的。当你不再需要内存时,你就增加了它的值——现在内存是“空闲”的。显然,这种方法的问题在于它是不可持续的——不能在块内释放(或分配)内存。因此,如果您为3个对象A、B、C分配了内存,并且不再需要对象B,那么就没有必要说B占用的内存可以自由使用-单堆栈指针根本没有这样做的能力

    这将堆栈内存的使用限制在“近距离接触”的情况下,即短暂的对象—当您知道不需要有选择地释放与在此范围内分配的对象相关联的任何内存,并且可以很快释放所有对象时。这使堆栈内存成为函数中定义的变量的理想存储—当函数退出时,所有这些变量一起被释放。更好的是,编译器可以自动为您执行此操作—您不必显式地告诉编译器何时释放每个变量的内存—一旦代码执行离开其作用域,它将自动释放

    还值得注意的是,堆栈分配和释放非常快——它们只需要一个寄存器算术运算

    然而,正如我前面所说的,stack有其局限性。堆内存就是为了克服这些问题,下面将对其进行描述

    堆 与堆栈(仅由简单寄存器管理)不同,堆内存由复杂的结构和逻辑支持。您可以从堆中请求内存,也可以将内存返回到堆中,并且可以独立地为每个对象执行此操作。因此,回到我的原始示例,当您为对象A、B和C请求内存(大小都相同),并且不再需要对象B时,您可以为B返回内存,但仍然保留A和C。如果您需要创建另一个与以前相同大小的对象D并为其请求内存,堆可以为您提供从B返回的内存。虽然不能保证这一点(堆算法非常复杂),但这是一个足够好的简化

    void foo() {
       int a;
    }
    
    int var1;
    
    void foo() {
        static int var2;
    }
    
    class A {
       static int var3;
    }
    
    void foo() {
       int* var4;
       // Here is the major source of confusion. var4 itself is **automatic**
       // you do not need to allocate or free var4 memory, so you can use it
       // like this:
       var4 = NULL; // Not an error!!!
       // However, you can't use the memory var4 points to yet!
       // Following line would cause incorrect behavior of the program:
       // *var4 = 42; // NEVER EVER!!!
       // Instead, you need to allocate the memory first (let's assume, we are in C++
       var4 = new int();
       // Now the memory was allocated, we can use it
       *var4 = 42; // Correct!
       // we no longer need this memory, so let's free it:
       delete var4;
       // This did not change var4 itself (unless there is a special case)
       // so technically, it still points to the memory which was former 
       // belonging to you. But the memory is no longer yours!!!
       // you can't read or write it!
       // Following code is bad-bad-bad:
       // int x = *var4; // NEVER EVER! 
    }