为什么删除指针不会使其变得不可用?

发布于 2024-11-28 03:12:38 字数 579 浏览 1 评论 0原文

因此,为了更好地理解new/delete(实际上是为了用小例子向自己证明为什么接口需要虚拟析构函数),我想了解内存泄漏,这样我就可以生活在对它们的恐惧之中。但可以这么说,我很难把漏水漏掉。实际上,我也很难使用 new/delete 。

这是我最简单的版本:

int* P1 = new int(43);

cout << "P1 = " << P1 << endl;
cout << "*P1 = " << *P1 << endl;

delete P1;

cout << "P1 = " << P1 << endl;
cout << "*P1 = " << *P1 << endl;

这打印:

P1 = 0xcc0340
*P1 = 43
P1 = 0xcc0340
*P1 = 43

我在类中做了一些更复杂的事情,但这个例子说明了我的失败。我认为删除需要一个指针并释放它的内存,从而使指针或至少它指向的内容无效?我一定是在做一些非常简单非常错误的事情。

So to understand new/delete better (really to prove to myself with small examples why virtual destructors are needed for interfaces), I want to understand memory leaks, so that I may live in fear of them. But I am having a hard time getting my leak on, so to speak; actually, I am have a hard time with new/delete too.

Here's my simplest version:

int* P1 = new int(43);

cout << "P1 = " << P1 << endl;
cout << "*P1 = " << *P1 << endl;

delete P1;

cout << "P1 = " << P1 << endl;
cout << "*P1 = " << *P1 << endl;

This prints:

P1 = 0xcc0340
*P1 = 43
P1 = 0xcc0340
*P1 = 43

I had something more complicated inside of a class, but this example illustrates my fail. I thought delete takes a pointer and frees it's memory, thereby invalidating the pointer or at least what it points to? I must be doing something very simple very wrong.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

那一片橙海, 2024-12-05 03:12:38

您正在造成未定义的行为。这意味着任何事情都可能发生。由于确实发生了某些事情,所以一切都按照记录进行。 (有时“某事”看起来与您可能错误地期望的其他事情非常相似。完全按照您认为想要实现的目标进行操作是“未定义行为”可能允许的实例之一。)

另请注意,“内存泄漏”是与您想要做的相反 - 在内存泄漏中您忘记释放内存,而您已经释放了内存并且现在正在访问无效内存。

这是真正的内存泄漏,它也不会导致未定义的行为——不要将“坏但正确”与“不正确”编程混淆!

int * factorial(int * n)
{
  if (*n == 0) return new int(1);
  else return new int(*n * *factorial(*n - 1));
}

You are causing undefined behaviour. This means that anything can happen. Since something did indeed happen, everything behaves as documented. (Sometimes "something" looks very similar to something else that you might erroneously expect. Doing exactly what you think you were trying to achieve is one of the possible allowed instances of "undefined behaviour".)

Note also that a "memory leak" is sort of the opposite of what you're trying to do - in a memory leak you forget to free memory, whereas you already freed the memory and are now accessing invalid memory.

Here's a real memory leak, which also does not cause undefined behaviour -- don't confuse "bad but correct" with "incorrect" programming!

int * factorial(int * n)
{
  if (*n == 0) return new int(1);
  else return new int(*n * *factorial(*n - 1));
}
站稳脚跟 2024-12-05 03:12:38

我一定是做了一些非常简单非常错误的事情。

你是绝对正确的。您的代码正在做一些非常简单非常错误的事情,并且您已经付出了最终的代价 - 没有看到任何负面结果。有时候,你做错了事,但并没有什么不好的事情发生。这是最糟糕的结果,因为您可能没有意识到您的代码是错误的,并且您将继续使用它,直到有一天您的代码意外崩溃,并且您不知道在哪里或如何,因为它以前总是有效的。它会在与实际错误部分完全无关的地方发生故障,您将花费数小时试图追踪它并找出它损坏的原因。

当你做错事时,这是未定义的行为。这意味着任何事情都可能发生。最好的情况是,你的代码崩溃,出现段错误,并且闪烁的灯亮起,表示“你正在使用释放的内存”,一切都非常清楚。在最坏的情况下,恶魔会从你的鼻子里飞出来。但除此之外,第二个最坏的可能结果是一切似乎都按照你的预期进行。

I must be doing something very simple very wrong.

You're absolutely right. Your code is doing something very simple very wrong, and you've paid the ultimate price - not seeing any negative results. Sometimes, you do things wrong, and nothing bad happens. This is the worst possible outcome, because you may not realize your code is wrong, and you'll continue to use it, until one day your code breaks unexpectedly, and you'll have no idea where or how because it's always worked before. It'll break somewhere completely irrelevant to the actual part that's wrong, and you'll spend hours trying to track it down and figure out why it's broken.

When you do things wrong, it's undefined behavior. That means anything can happen. At best, your code crashes and segfaults and blinking lights come on saying "YOU'RE USING FREED MEMORY" and everything is very clear. At worst, demons fly out of your nose. But just above that, the second worst possible outcome is that everything appears to work as you intended it to.

热血少△年 2024-12-05 03:12:38

这将是内存泄漏:

int* P1 = new int(43);
     P1 = new int(42);

分配内存而不再次删除它。

This would be a memory leak:

int* P1 = new int(43);
     P1 = new int(42);

Allocating memory without deleting it again.

凉宸 2024-12-05 03:12:38

此代码

delete P1;

cout<<"P1 = "<<P1<<endl;
cout<<"*P1 = "<<*P1<<endl;

会导致未定义的行为。所以任何事情都可能发生。更容易导致内存泄漏:

for(;;) new int;

This code

delete P1;

cout<<"P1 = "<<P1<<endl;
cout<<"*P1 = "<<*P1<<endl;

causes undefined-behavior. So anything can happen. It's much easier to cause a memory leak:

for(;;) new int;
装纯掩盖桑 2024-12-05 03:12:38
// Reserve some memory for an int and set that memory to the value 43.
int* P1 = new int(43);

// Print the address of the reserved memory.
cout<<"P1 = "<<P1<<endl;
// Print the contents of that memory.
cout<<"*P1 = "<<*P1<<endl;

// Free the memory - it is no longer reserved to you.
delete P1;

// int* P2 = new int(47);    

// Print the address of the memory. It still holds the address to 
// the memory that used to be reserved for you.
cout<<"P1 = "<<P1<<endl;

// Print the current value of the memory that used to be reserved.
cout<<"*P1 = "<<*P1<<endl;

如果您取消注释 P2 行,则很可能会为其分配相同的内存,这将更改最后一行打印的值。

正如其他人指出的那样,访问已通过删除释放的内存会导致未定义的行为。未定义包括在某些情况下以奇怪的方式崩溃(也许仅在满月期间?;-)。它还包括目前运行良好的所有内容,但该错误是一个地雷,每当您在程序中的其他任何地方进行其他更改时,该错误都可能会触发。

内存韭菜是指您使用 new 分配内存,但从未使用 delete 释放内存。除非有人长时间运行您的程序并发现它耗尽了系统的所有内存,否则通常不会注意到这一点。

// Reserve some memory for an int and set that memory to the value 43.
int* P1 = new int(43);

// Print the address of the reserved memory.
cout<<"P1 = "<<P1<<endl;
// Print the contents of that memory.
cout<<"*P1 = "<<*P1<<endl;

// Free the memory - it is no longer reserved to you.
delete P1;

// int* P2 = new int(47);    

// Print the address of the memory. It still holds the address to 
// the memory that used to be reserved for you.
cout<<"P1 = "<<P1<<endl;

// Print the current value of the memory that used to be reserved.
cout<<"*P1 = "<<*P1<<endl;

If you would uncomment the P2 line, it is quite likely that it would be assigned the same memory which would change the value printed at the last line.

Accessing memory that has been freed with delete causes undefined behaviour as others have pointed out. Undefined includes crashing in strange ways on some cases (only during full moon perhaps? ;-). It also includes everything working perfectly well for now, but with the bug being a mine that can trip off whenever you make another change anywhere else in your program.

A memory leek is when you allocate memory with new and never free it with delete. This will usually not be noticed until someone runs your program for a longer period and finds out that it eats all the memory of the system.

不即不离 2024-12-05 03:12:38

正如已经解释的那样,取消引用已删除的指针是未定义的行为,即您做错了什么。编译器可能会通过将指针的值更改为某个神奇值来帮助您发现该错误,该值总是会导致取消引用指针失败,并且可以给您一个线索,表明它是因为之前删除的。

快速测试显示了我的以下行为:
MSVC2010:
调试版本:*P1 = 0xfeeefeee
发布版本:*P1 = <随机>
海湾合作委员会 4.6:
调试与发布版本: *P1 = 0

所以你只是(不)幸运地再次获得了原始值。我建议您始终在调试模式下构建来测试您的程序(即使您没有进行调试),因为它会为您的代码添加额外的健全性检查。

Dereferencing a deleted pointer is undefined behavior, as already explained, i.e. you are doing something wrong. Compilers may help you find that error by changing the pointer's value to some magic value that will always cause dereferencing the pointer to fail and can give you a clue that it's because it was previously deleted.

A quick test showed the following behavior for me:
MSVC2010:
debug build: *P1 = 0xfeeefeee
release build: *P1 = <random>
GCC 4.6:
debug & release builds: *P1 = 0

So you were just (un)lucky that you got again the original value. I recommend you to always build in debug mode for testing your programs (even if you aren't debugging) because it adds additional sanity checks to your code.

信愁 2024-12-05 03:12:38

内存被释放但未被清理。该值可能会保留在内存中,直到其他进程在该位置写入新值。

The memory is freed but it is not cleaned. The value may stay in memory until some other process writes a new value in that location.

眼藏柔 2024-12-05 03:12:38

删除不会使指针无效。它释放它指向的内存返回堆。在这种情况下,内存没有被重用,因此仍然包含相同的内容。在某些时候,内存将被重用,然后你就会得到其他人所说的未定义的行为。

但这不是内存泄漏。当您将指针指向另一个内存分配(或只是丢弃指针)而不释放它指向的内存时。然后第一个保持分配状态,并且由于您没有对它的引用,因此您无法释放它。

Delete doesn't invalidate the pointer. It releases the memory it points to back to the heap. In this case, the memory hasn't been reused and therefore still contains the same content. At some point that memory WILL be reused and then you get the undefined behavior that others speak of.

This isn't a memory leak though. That's when you point the pointer to another memory allocation (or just discard the pointer) without freeing the memory it points to. The first then stays allocated and, as you've no references to it, you've no way of freeing it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文