简体   繁体   English

C++ 删除一个指针(空闲内存)

[英]C++ delete a pointer (free memory)

Consider the following code:考虑以下代码:

int a = 10;
int * b = &a;
int * c = b;
delete b; // equivalent to delete c;

Am I correct to understand in the last line, delete b and delete c are equivalent, and that both will free the memory space holding a , thus a is no longer accessible?我对最后一行的理解是否正确, delete bdelete c是等效的,并且两者都将释放保存a的内存空间,因此a不再可访问?

The behaviour of your program is undefined .你的程序的行为是undefined You can only use delete on a pointer to memory that you have allocated using new .只能在使用new分配的内存指针上使用delete If you had written如果你写过

int* b = new int;
*b = 10;
int* c = b;

then you could write either delete b;然后你可以或者delete b; or delete c;delete c; to free your memory.释放你的记忆。 Don't attempt to derefererence either b or c after the delete call though, the behaviour on doing that is also undefined .不要尝试在delete调用之后取消引用bc ,这样做的行为也是undefined

If b and c point to the same memory then deleting either of them releases the memory so that assumption is correct.如果bc指向相同的内存,则删除它们中的任何一个都会释放内存,因此假设是正确的。 a becoming inaccessible is not correct in this case though as you do not point to dynamically allocated memory and you can only call delete / delete[] on something that was created with new / new[] . a不可访问是不是在这种情况下,正确的,虽然你不指向动态分配的内存,你只能叫delete / delete[]对与创建一些new / new[] Trying to delete / delete[] a pointer that was not allocated with new / new[] is undefined behavior and will generally end in a segmentation fault.尝试delete / delete[]一个没有用new / new[]分配的指针是未定义的行为,通常会以段错误结束。

The confusing part is that the answer to your question令人困惑的部分是您问题的答案

Am I correct to understand in the last line, delete b and delete c are equivalent"我在最后一行中的理解是否正确,删除 b 和删除 c 是等效的”

Is yes, they're equivalent, and both UB as mentioned everywhere else here.是的,它们是等效的,并且这里的其他地方都提到了 UB。

you should never use delete for variable that allocated on stack, delete is the counterpart of new.你永远不应该对在堆栈上分配的变量使用 delete,delete 是 new 的对应物。 hence no delete/free is needed when no new/alloc is used, once you are out of the "scope" of the code ( in this case the program itself ) all memory is considered available.因此,当不使用 new/alloc 时,不需要删除/释放,一旦超出代码的“范围”(在这种情况下是程序本身),所有内存都被认为是可用的。

This particular answer uses a particular implementation of the heap to go into detail about what would happen in your proposed situation; 这个特定的答案使用堆的特定实现来详细说明在您提出的情况下会发生什么; however this matters very little as other versions would still have similar issues close to the argument I provide. 然而这很重要,因为其他版本仍然会有类似的问题接近我提供的论点。

The answer is "no", and it is because of what other people have said. 答案是“不”,这是因为其他人所说的。 However, I am going to be a bit more precise, because I think you don't actually know what the stack and heap are and so I'm going to take the time to explain that you. 但是,我会更准确一些,因为我认为你实际上并不知道堆栈和堆是什么,所以我会花时间来解释你。

Now first off, everything I'm saying in terms of details about the heap are a "lie". 现在首先,关于堆的细节,我所说的一切都是“谎言”。 Nobody knows specifically what your compiler does to implement the heap. 没有人具体知道您的编译器实现堆的功能。 So I can only give my understanding of a heap instead. 所以,我只能给我一堆的理解来代替。

New and delete are actually two functions (if you've heard of operator overloading you'll understand what I mean by this) that accept pointers and modify a data structure in memory known as the heap. 新建和删除实际上是两个函数(如果你已经听说过运算符重载,你会理解我的意思)接受指针并修改内存中的数据结构,称为堆。 It one of four main data structures in a C/C++ program's memory (the heap, the stack, the text, and the static space). 它是C / C ++程序内存中的四个主要数据结构之一(堆,堆栈,文本和静态空间)。

The heap is essentially a linked list but instead of storing data in each node, you cram the data in between them. 堆本质上是一个链表,但不是在每个节点中存储数据,而是将数据填入它们之间。 If you are unfamiliar with a linked list, then in this context it is a two component "array" sitting in raw memory. 如果您不熟悉链接列表,那么在此上下文中,它是一个位于原始内存中的双组件“数组”。 The second component is the length of the block stored in front of it. 第二个组件是存储在它前面的块的长度。 The first component is the length of the block before it. 第一个组件是它之前的块的长度。 In this manner it easy to find a block as it is just a matter of moving down the list searching for a block. 以这种方式很容易找到一个块,因为它只是向下移动列表搜索块。 Usually (because programs are not even close to being complex enough to need 2^31 bytes allocated within a single block) the leftmost bit is used as a true/false value saying whether the block is free. 通常(因为程序甚至不够复杂到需要在单个块内分配2 ^ 31个字节),最左边的位用作表示块是否空闲的真/假值。 Hence free and new are just operations upon the list and free simply backs the pointer up by one to look at the node and make appropriate changes. 因此,free和new只是列表上的操作而且free只需将指针向上移动一个来查看节点并进行适当的更改。 I won't go into more detail because those familiar with doubly linked lists should understand the operations and if you don't understand, there's no point in me trying to teach you something you'll learn in a much grander depth later. 我不会详细介绍,因为那些熟悉双重链表的人应该理解这些操作,如果你不理解,那我就没有必要教你一些你将在更深层次的深度学习的东西。

Remember: Your implementations will vary by compiler. 请记住:您的实现因编译器而异。 This is just an example. 这只是一个例子。

The stack on the other is where your local variables are. 另一方面,堆栈是局部变量所在的位置。 It's literally a giant array of arrays. 它实际上是一个庞大的数组阵列。 The middle of the array holds the address in the code where the program should return to after execution, and then the parameters are on one side whereas the local variables are on the other. 数组的中间保存程序执行后应返回的代码中的地址,然后参数位于一侧,而局部变量位于另一侧。 The local variables have no clear sense of organization. 局部变量没有明确的组织意识。 Some compilers may detect that one value stops being used before another and just shares the memory location (you'd never notice unless you actually peeked in memory or scanned the stack). 有些编译器可能会检测到一个值在另一个值之前停止使用并且只是共享内存位置(除非你真正偷看内存或扫描堆栈,否则你永远不会注意到)。

As you can see, the two simply don't make sense. 如你所见,这两者根本没有意义。 Calling free on a pointer indexing the stack means your trying to perform the list operation on the stack. 在索引堆栈的指针上自由调用意味着您尝试在堆栈上执行列表操作。 One of two things will happen: 将发生以下两件事之一:

  1. Your implementation detects the memory is not even in the heap and blows up with an error message (illegal argument exception). 您的实现检测到内存甚至不在堆中,并且出现错误消息(非法参数异常)。

  2. The implementation is "dumb" and actually tries to perform the list operation. 实现是“哑”,实际上尝试执行列表操作。 This means the value before the variable in memory will be altered and other values might be altered in an attempt to "merge" two free blocks into one larger block. 这意味着内存中变量之前的值将被更改,并且可能会更改其他值以尝试将两个空闲块“合并”为一个更大的块。

Simply put: don't do that. 简单地说:不要那样做。 You might break something in your program. 你可能会在程序中破坏某些东西。 What if you messed up the return line? 如果你搞砸了回程线怎么办? Next thing you know, you'd have an infinite loop of function calls yet... you wrote no loops. 接下来你知道,你有一个无限的函数调用循环......你没有写过循环。 Very very bad. 非常非常糟糕。

And of course: 而且当然:

Your exact implementation of the heap will vary wildly, unlike the stack which doesn't tend to change much. 你对堆的确切实现会有很大的不同,不像堆栈不会发生太大变化。

For instance, while I have never actually seen the code or a diagram of the raw memory of such a structure I have heard that there are models of the heap space built around there being two separate lists holding the freed blocks and the allocated blocks. 例如,虽然我从未真正看到过这种结构的原始内存的代码或图表,但我听说有堆空间的模型围绕着两个单独的列表来保存释放的块和分配的块。 This wouldn't affect the question though as there is still some form of internal bookkeeping that deals with the allocation. 这不会影响这个问题,因为仍有某种形式的内部簿记处理分配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM