在C ++中删除指针


91

背景信息:我想把指针包裹住,几个星期前我们刚在学校看到它们,今天练习的时候我遇到了傻子吗?问题,对您来说可能非常简单,但是我几乎没有编程经验。

我已经在SO中看到了很多有关删除指针的问题,但它们似乎都与删除类有关,而不是与“简单”指针(或任何适当的术语)有关,这是我正在尝试的代码跑:

#include <iostream>;

using namespace std;

int main() {
  int myVar,
      *myPointer;

  myVar = 8;
  myPointer = &myVar;

  cout << "delete-ing pointers " << endl;
  cout << "Memory address: " << myPointer << endl;

  // Seems I can't *just* delete it, as it triggers an error 
  delete myPointer;
  cout << "myPointer: " << myPointer << endl;
  // Error: a.out(14399) malloc: *** error for object 0x7fff61e537f4:
  // pointer being freed was not allocated
  // *** set a breakpoint in malloc_error_break to debug
  // Abort trap: 6

  // Using the new keyword befor deleting it works, but
  // does it really frees up the space? 
  myPointer = new int;
  delete myPointer;
  cout << "myPointer: " << myPointer << endl;
  // myPointer continues to store a memory address.

  // Using NULL before deleting it, seems to work. 
  myPointer = NULL;
  delete myPointer;
  cout << "myPointer: " << myPointer << endl;
  // myPointer returns 0.

}

所以我的问题是:

  1. 为什么第一种情况不起作用?似乎最直接的使用方式是使用和删除指针?该错误表明未分配内存,但'cout'返回了一个地址。
  2. 在第二个示例中,未触发错误,但是对myPointer的值进行计算仍然返回内存地址?
  3. #3真的有效吗?似乎对我有用,指针不再存储地址,这是删除指针的正确方法吗?

很长的问题,很抱歉,想让这个问题尽可能清楚,还要重申,我几乎没有编程经验,所以如果有人可以使用外行的术语回答这个问题,将不胜感激!


16
您没有看到第一个示例的原因是因为它是错误的。只有deletenew。删除指针后,也不需要将其自身设置为NULL。如果您想在那里安全,请使用智能指针,这些指针可以为您释放内存,并在您尝试不使用它们保存某些东西时出错。
克里斯

嗯,好的,我不确定是什么智能指针,但是我会仔细研究,谢谢!
利比里亚2012年

1
简而言之,它们按照我的描述进行。为了保留新的东西,您打电话给reset它并释放旧的东西。要释放它而不更换它,请致电release。当它超出范围时,它将被销毁,并可以根据其类型释放内存。std::unique_ptr只供一个所有者使用。std::shared_ptr当最后一个所有者停止拥有该资源时,将其释放。它们也是异常安全的。如果您分配一个资源,然后遇到异常,则该资源将被正确释放。
克里斯,2012年

Answers:


164

1和2

myVar = 8; //not dynamically allocated. Can't call delete on it.
myPointer = new int; //dynamically allocated, can call delete on it.

第一个变量分配在堆栈上。您只能使用new运算符在动态分配的内存(在堆上)上调用delete 。

3。

  myPointer = NULL;
  delete myPointer;

上面什么也没做。您没有释放任何东西,因为指针指向NULL。


不应执行以下操作:

myPointer = new int;
myPointer = NULL; //leaked memory, no pointer to above int
delete myPointer; //no point at all

您将其指向NULL,留下了泄漏的内存(您分配的新int)。您应该释放所指向的内存。无法再访问已分配的方法new int,因此会导致内存泄漏。


正确的方法:

myPointer = new int;
delete myPointer; //freed memory
myPointer = NULL; //pointed dangling ptr to NULL

更好的方法:

如果您使用的是C ++,请不要使用原始指针。使用智能指针代替它可以为您处理这些事情,而开销很小。C ++ 11附带了几个


13
<pedantry>“在堆栈上”是一个实现细节-C ++明显避免提及。较正确的术语是“具有自动存储期限”。(C ++
11,3.7.3

4
谢谢,我选择了您的答案是:a)解释了错误所在,b)给出了最佳实践,非常感谢!
Leopic

6
@Tqn这是不对的。delete myPointer解除分配*myPointer。那是正确的。但是myPointer继续指向已释放并且不应该使用的内存位置,因为它是UB。仅当它首先是局部变量时,才可以在作用域结束后访问它。
Anirudh Ramanathan 2014年

2
@DarkCthulhu谢谢!(我从字面上看)new每天都学点东西。(我很俗气!)
Tqn 2014年

1
@AmelSalibasic与堆栈上的变量关联的内存仅在其超出范围时才被释放。将其分配给NULL可以防止我们以后滥用它。
Anirudh Ramanathan 2014年

23

我相信您还没有完全了解指针的工作方式。
当您有一个指向某些内存的指针时,您必须了解三件事:
-指针(内存)有“所指向的内容”
-该内存地址
-并非所有指针都需要删除其内存:您只需需要删除动态分配的内存(使用的new运算符)。

想像:

int *ptr = new int; 
// ptr has the address of the memory.
// at this point, the actual memory doesn't have anything.
*ptr = 8;
// you're assigning the integer 8 into that memory.
delete ptr;
// you are only deleting the memory.
// at this point the pointer still has the same memory address (as you could
//   notice from your 2nd test) but what inside that memory is gone!

你什么时候做

ptr = NULL;
// you didn't delete the memory
// you're only saying that this pointer is now pointing to "nowhere".
// the memory that was pointed by this pointer is now lost.

C ++允许您尝试指向delete一个指向的指针,null但是它实际上并没有做任何事情,只是没有给出任何错误。


2
谢谢,这对我很有帮助,我以为我已经删除了所有指针,不知道那仅适用于那些新指针,谢谢。
Leopic

13

指针与普通变量相似,因为您不需要删除它们。在函数执行结束和/或程序结束时将它们从内存中删除。

但是,您可以使用指针分配内存的“块”,例如:

int *some_integers = new int[20000]

这将为20000整数分配内存空间。之所以有用,是因为堆栈的大小有限,您可能想在没有堆栈溢出错误的情况下处理大量的“ ints”。

每当调用new时,都应在程序末尾“删除”,因为否则会发生内存泄漏,并且某些分配的内存空间将永远不会返回供其他程序使用。去做这个:

delete [] some_integers;

希望能有所帮助。


1
我只想补充一点,分配的内存将返回给其他程序使用,但是只有在您的程序完成执行之后。
sk4l16年

7

在C ++中有一条规则,对于每个规则都有一个delete

  1. 为什么第一种情况不起作用?似乎最直接的使用方式是使用和删除指针?该错误表明未分配内存,但'cout'返回了一个地址。

从来没有叫过。因此,cout打印的地址是myVar的内存位置的地址,或者在这种情况下是分配给myPointer的值。通过写:

myPointer = &myVar;

你说:

myPointer = myVar中数据存储的地址

  1. 在第二个示例中,未触发错误,但是对myPointer的值进行计算仍然返回内存地址?

它返回一个指向已删除的存储位置的地址。因为首先创建指针并将其值分配给myPointer,然后再删除它,然后再打印就可以了。因此,除非您为myPointer分配另一个值,否则删除的地址将保留。

  1. #3真的有效吗?似乎对我有用,指针不再存储地址,这是删除指针的正确方法吗?

NULL等于0,则删除0,因此不删除任何内容。逻辑上说它打印0是因为您这样做了:

myPointer = NULL;

等于:

myPointer = 0;

4
  1. 您试图删除分配在堆栈上的变量。你不能做这个
  2. 删除指针实际上并不会破坏指针,只是将占用的内存返回给OS。您可以访问它,直到将内存用于其他变量或进行其他操作为止。因此,优良作法是在删除后将指针设置为NULL(0)。
  3. 删除NULL指针不会删除任何内容。

1
int value, *ptr;

value = 8;
ptr = &value;
// ptr points to value, which lives on a stack frame.
// you are not responsible for managing its lifetime.

ptr = new int;
delete ptr;
// yes this is the normal way to manage the lifetime of
// dynamically allocated memory, you new'ed it, you delete it.

ptr = nullptr;
delete ptr;
// this is illogical, essentially you are saying delete nothing.

1
此外,请查看有关指针框架youtube.com/watch?v=bjObm0hxIYYyoutube.com/watch?v=Rxvv9krECNw的堆栈框架的讲座。
卡斯珀·拜耶
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.