c++ - (C++) 当函数完成时分配在堆栈上的数组发生了什么?

标签 c++ memory-management

我有多年的 Java 开发经历,现在我想转向 C++,我很难理解内存管理系统。

让我用一个小例子来解释一下情况:

根据我的理解,您可以在堆栈或堆上分配空间。第一个是通过声明这样的变量来完成的:

 int a[5]

int size = 10;
int a[size]

相反,如果你想在堆上分配内存,那么你可以使用“new”命令来完成。例如像:

int *a = new int[10]; (notice that I haven't tried all the code, so the syntax might be wrong)

两者之间的一个区别是,如果它是在函数完成时在堆栈上分配的,那么空间会自动释放,而在另一种情况下,我们必须使用 delete() 显式释放它。

现在,假设我有一个这样的类:

class A {
  const int *elements[10];

  public void method(const int** elements) {
    int subarray[10];
    //do something
    elements[0] = subarray;
  }
}

现在,我有几个问题:

  1. 在这种情况下,子数组分配在堆栈上。为什么在函数方法完成后,如果我查看 elements[0] 我仍然看到子数组的数据?编译器是否翻译了堆分配中的第一个分配(在这种情况下,这是一种好的做法)吗?
  2. 如果我将子数组声明为“const”,那么编译器不会让我将它分配给元素。为什么不?我还以为const只是不能改变指针,其他的都没有。
  3. (这可能很愚蠢)假设我想分配“元素”,而不是使用固定的 10 个元素,而是使用来自构造函数的参数。是否仍然可以在堆栈中分配它,或者构造函数将始终在堆中分配它?

很抱歉提出这样的问题(对于专业的 C 程序员来说这可能看起来很愚蠢),但是 C++ 的内存管理系统与 Java 非常不同,我想避免泄漏或缓慢的代码。非常感谢!

最佳答案

a) in this case, subarray is allocated on the stack. Why after the function method has finished, if I look on elements[0] I still see the data of subarray? Has the compiler translated the first allocation in a heap allocation (and in this case, is this a good practice)?

这叫做“未定义行为”,任何事情都有可能发生。在这种情况下,subarray 保存的值仍然存在,顺便说一句,可能是因为您在函数返回后立即访问了该内存。但是您的编译器也可以在返回之前将这些值清零。你的编译器也可以将喷火龙送到你家。在“未定义行为”领域,任何事情都可能发生。

b) if I declare subarray as "const", then the compiler does not let me assign it to elements. Why not? I thought that the const only concerns the inability to change the pointer, but nothing else.

这是语言的一个相当不幸的怪癖。考虑

const int * p1; // 1
int const * p2; // 2
int * const p3; // 3
int * p4;       // 4
int const * const p5; // 5

这都是有效的 C++ 语法。 1 表示我们有一个指向const int可变 指针。 2 表示与 1 相同(这是怪癖)。 3 表示我们有一个指向可变整数常量指针。 4 表示我们有一个指向可变整数 的普通旧可变指针。 5 表示我们有一个指向 const intconst 指针。规则大致是这样的:从从右到左读取常量,除了最后一个常量,它可以在右边或左边。

c) suppose I want to allocate "elements" not with a fixed 10 elements, but with a parameter that comes from the constructor. Is it still possible to allocate it in the stack, or the constructor will always allocate it in the heap?

如果您需要动态分配,那么这将通常在堆上,但堆栈和堆的概念是依赖于实现的(即无论您的编译器供应商做什么)。

最后,如果您有 Java 背景,那么您需要考虑内存的所有权。例如,在您的方法 void A::method(const int**) 中,您将指针指向本地创建的内存,而该内存在方法返回后消失。您的指针现在指向没有人拥有的内存。最好将该内存实际复制到一个新区域(例如,A 类的数据成员),然后让您的指针指向 block 内存。 此外,虽然 C++ 可以使用指针,但明智的做法是不惜一切代价避免使用它们。例如,在可能和适当的情况下尽量使用引用而不是指针,并对任意大小的数组使用 std::vector 类。此类还将处理所有权问题,因为将一个 vector 分配给另一个 vector 实际上会将所有元素从一个 vector 复制到另一个 vector (除了现在使用右值引用,但暂时忘记这一点)。有些人认为“裸”新建/删除是糟糕的编程习惯。

关于c++ - (C++) 当函数完成时分配在堆栈上的数组发生了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19121820/

相关文章:

c++ - 在访问者模式中检索类模板的类型

c++ - 接受参数的函数指针

c++ - 将 QByteArray 转换为无符号短整型 : not as expected

c - c 中的内存损坏

java - 两个 JVM 之间的共享内存

c++ - DirectX11 2 窗口渲染

C++ - 直接插入 std::map 而不使用赋值运算符

linux - Kmemcheck 输出位置

c++ - 如何构建垃圾收集器?

java - 动态多维 Java 结构替换静态多维数组