请考虑以下代码:
int a = 10;
int * b = &a;
int * c = b;
delete b; // equivalent to delete c;
我在最后一行中是否正确理解,delete b
和delete c
是等效的,两者都将释放持有a
的内存空间,因此a
为否更容易接近?
答案 0 :(得分:42)
您的程序的行为是 undefined 。您只能 在指向使用delete
分配的内存的指针上使用new
。如果你写了
int* b = new int;
*b = 10;
int* c = b;
然后你 可以 delete b;
或 delete c;
来释放你的记忆。在b
调用之后,不要尝试 derefererence c
或delete
,这样做的行为也是 undefined
答案 1 :(得分:5)
如果b
和c
指向相同的内存,则删除其中任何一个都会释放内存,以便假设正确。在这种情况下,a
无法访问是不正确的,因为您没有指向动态分配的内存,而且您只能对使用delete
创建的内容调用delete[]
/ new
/ new[]
。尝试delete
/ delete[]
未使用new
/ new[]
分配的指针是未定义的行为,通常会以分段错误结束。
答案 2 :(得分:5)
令人困惑的部分是你的问题的答案
我在最后一行是否正确理解,删除b和删除c是等效的"
是的,他们是等同的,并且UB都在这里的其他地方提到过。
答案 3 :(得分:0)
你永远不应该对堆栈上分配的变量使用delete, 删除是新的对应物。 因此,当你没有使用新的/ alloc时,一旦你不在"范围内,就不需要删除/免费。代码(在这种情况下是程序本身)所有内存都被认为是可用的。
答案 4 :(得分:0)
这个特定的答案使用堆的特定实现来详细说明在您提议的情况下会发生什么;然而这很重要,因为其他版本仍然会有类似的问题接近我提供的论点。
答案是" no",这是因为其他人所说的。但是,我会更准确一些,因为我认为你实际上并不知道堆栈和堆是什么,所以我会花时间来解释你。
现在首先,关于堆的详细信息,我所说的一切都是"谎言"。没有人具体知道您的编译器实现堆的功能。所以我只能让我理解 a 堆。
新增和删除实际上是两个函数(如果您已经听说过运算符重载,您将理解我的意思)接受指针并修改内存中称为堆的数据结构。它是C / C ++程序内存中的四个主要数据结构之一(堆,堆栈,文本和静态空间)。
堆本质上是一个链表,但不是在每个节点中存储数据,而是将数据填入它们之间。如果您不熟悉链接列表,那么在此上下文中它是一个双组件"数组"坐在原始记忆中。第二个组件是存储在它前面的块的长度。第一个组件是它之前的块的长度。以这种方式很容易找到一个块,因为它只是向下移动列表搜索块。通常(因为程序甚至不够复杂到需要在单个块内分配2 ^ 31个字节),最左边的位用作表示块是否空闲的真/假值。因此,free和new只是列表上的操作而且free只需将指针向上移动一个来查看节点并进行适当的更改。我不会详细了解,因为那些熟悉双重链表的人应该了解操作,如果你不理解,那我就没有必要教你一些你自己的东西了。在以后更深入的学习。
请记住:您的实现因编译器而异。这只是一个例子。
另一个堆栈是局部变量所在的位置。它实际上是一个庞大的数组阵列。数组的中间保存程序执行后应返回的代码中的地址,然后参数位于一侧,而局部变量位于另一侧。局部变量没有明确的组织意识。有些编译器可能会检测到一个值在另一个值之前停止使用并且只是共享内存位置(除非您实际窥视内存或扫描堆栈,否则您将永远不会注意到。)
正如你所看到的,这两者根本没有意义。在索引堆栈的指针上自由调用意味着您尝试在堆栈上执行列表操作。将发生以下两件事之一:
您的实现检测到内存甚至不在堆中并且出现错误消息(非法参数异常)。
实施是"哑巴"并实际上尝试执行列表操作。这意味着内存中变量之前的值将被更改,其他值可能会被更改以尝试合并"两个空闲区块分成一个更大的区块。
简单地说:不要这样做。你可能会在程序中破坏某些东西。如果你搞砸了回程线怎么办?接下来你知道,你有一个无限的函数调用循环......你没有写过循环。非常糟糕。
当然:
您的堆的确切实现会有很大差异,与不会发生太大变化的堆栈不同。
例如,虽然我从未真正看到过这种结构的原始内存的代码或图表,但我听说有一些堆空间模型围绕着两个独立的列表来保存释放的块和分配的块。这不会影响问题,因为仍有某种形式的内部簿记可以处理分配。