C++ C+中的存储持续时间与位置+;

C++ C+中的存储持续时间与位置+;,c++,memory,memory-management,storage-duration,C++,Memory,Memory Management,Storage Duration,有时,我发现在存储的持续时间和在何处发生这种情况之间存在着各种概念的混合。这是因为有时我会看到以下陈述: int i; // This is in the stack! int* j = new int; // This is in the heap! 但这真的是百分之百的真实吗?C++是否确保存储发生在哪里?或者,它是由编译器决定的 存储位置是否独立于持续时间? 例如,以这两个片段为例: void something() { int i; std::cout << "

有时,我发现在存储的持续时间和在何处发生这种情况之间存在着各种概念的混合。这是因为有时我会看到以下陈述:

int i; // This is in the stack!
int* j = new int; // This is in the heap!
但这真的是百分之百的真实吗?C++是否确保存储发生在哪里?或者,它是由编译器决定的

存储位置是否独立于持续时间?

例如,以这两个片段为例:

void something()
{
   int i;
   std::cout << "i is " << i << std::endl;
}
vs:

这两种情况应该放在堆中以避免堆栈溢出(或者至少是到目前为止我被告知的…),除了存储持续时间之外,编译器是否也考虑了这一点

存储位置是否独立于持续时间

A0:持续时间指定预期/要求的行为。
A1:本标准未规定如何实施。
A2:标准甚至不需要堆或堆栈

void something()
{
   int i;
   std::cout << "i is " << i << std::endl;
}

void something()
{
   int* i = new int;
   std::cout << "i is " << i << std::endl;
   delete i;
}
这确实很大。某些实现可能无法在堆栈上支持此功能(堆栈帧大小可能受到操作系统、硬件或编译器的限制)

一个完全有效的实现是为此动态分配内存,并确保在对象超出范围时释放内存

另一个实现是不在堆栈上而是在
bzz
中预先分配内存(从这里的内存开始。这是存储内存的应用程序的汇编程序区域)。只要它实现了在作用域末尾调用任何析构函数的预期行为(我知道int没有析构函数,所以这很容易)

<> C++是否确保存储发生在哪里?还是由编译器决定

当您声明一个变量时,如:

int i;
它有自动存储功能。它可能确实在堆栈上,但如果有足够的寄存器可用,则通常只为它分配一个寄存器。从理论上讲,编译器为这个变量分配堆内存也是有效的,但在实践中这并没有发生

使用
new
时,实际上由标准库为您分配内存。通过default,它将使用堆。然而,理论上它也可以在堆栈上分配内存,但这通常是错误的,因为当您从调用
new
的函数返回时,任何堆栈存储都会消失

事实上,
new
只是一个操作符,就像
+
,您可以重载它。通常,您可以在类中重载它,但也可以重载全局
new
操作符(类似地,还有
delete
操作符),并让它根据需要分配存储

存储位置是否独立于持续时间

原则上是的,但实际上,只有函数持续时间的自动变量被放置在堆栈上,而使用
new
分配的数据通常要比调用它的函数的生命周期长,并且要放在堆上

这两种情况应该放在堆中以避免堆栈溢出(或者至少是到目前为止我被告知的…),除了存储持续时间之外,编译器是否也考虑了这一点


据我所知,GCC和Clang从未对具有自动存储的变量使用堆分配,无论其大小如何。因此,您必须自己使用
new
delete
,或者使用一个容器为您管理存储。一些容器,如<>代码> STD::String ,如果只存储少量元素,则避免堆分配。

堆栈/堆的概念不是C++标准的一部分。用这些术语来考虑对象也没有什么帮助(考虑动态分配的类的int成员)。仅从存储持续时间的角度考虑对象。@考虑堆栈/堆可能有用或必要,即使它不是标准的一部分。例如,
intn[100000000]示例可能会在大多数系统上导致堆栈溢出。您是否询问它是如何在内部实现的?
new
操作符可以通过多种方式实现,它还可以使用堆栈中分配的内存。在常见的实现(如G++和Visual Studio)中,函数外部的变量定义不在堆栈中分配。它们分配在既不是堆栈也不是堆的内存段中。该区域通常是放置所有全局变量的位置。通常,此内存区域是由可执行文件格式(例如预定义的位置)分配的。@interjay这就是为什么具有这些限制的有效实现甚至可能不会将堆用于该变量的原因。因此,加倍强调我关于思考这些事情的观点是有害的是打破堆栈的一种简单方法。某些实现的堆栈帧大小有限,并且该对象不适合堆栈帧限制。为了正确地实现这一点,编译器需要在这些系统上动态地分配它(或者发出一个警告,说明已经超过了实现限制)。
void something()
{
  int* n = new int[100000000];
  delete n;
}
void something()
{
   int i;
   std::cout << "i is " << i << std::endl;
}

void something()
{
   int* i = new int;
   std::cout << "i is " << i << std::endl;
   delete i;
}
int n[100000000]; // Man this is big
int i;