这是C ++中的double free吗?

问题描述

我认为以下代码片段将导致double free,并且该程序将进行核心转储。但是事实是我运行代码时没有错误吗?

Similar problem表明它引起了双重释放!

我的问题是,为什么没有错误表明有双重免费?为什么没有核心转储?

#include <iostream>
using namespace std;

int main()
{
    int *p = new int(5);
    cout << "The value that p points to: " << (*p) << endl;
    cout << "The address that p points to: " << &(*p) << endl;
    delete p;
    cout << "The value that p points to: " << (*p) << endl;
    cout << "The address that p points to: " << &(*p) << endl;
    delete p;
    cout << "The value that p points to: " << (*p) << endl;
    cout << "The address that p points to: " << &(*p) << endl;
    delete p;
}

我运行该程序时该程序的输出如下所示:

Program output

在修改了如下代码段之后,发生了核心转储:

#include <iostream>
using namespace std;

int main()
{
    int *p = new int(5);
    for (;;)
    {
        cout << "The value that p points to: " << (*p) << endl;
        cout << "The address that p points to: " << &(*p) << endl;
        delete p;
    }
    return 0;
}

程序输出为:

Modified program output

还有另一个问题,为什么这个程序每次都会核心转储?

解决方法

是的,它是双free(真的,三重),将其置于未定义的行为范围内。

但这就是关于未定义行为的阴险 ,不是要求崩溃或抱怨,完全不需要 做任何事情(a)。它甚至可以起作用。

我可以设想一个实现,该实现将块的空闲状态存储在其控制信息中,这样两次释放就不会产生任何效果。但是,这将是低效的,并且也不会涵盖已将其重新分配用于其他目的的情况(这将防止双重释放,但是当另一些代码仍然认为它仍然具有该代码块时,则不会有一段代码释放该块)

因此,鉴于不需要工作,建议您 避免使用它,因为它可能下载{{ 1}},然后在擦除主驱动器时播放它。

顺便说一句,现代C ++具有能够管理其 own 生命周期的智能指针,如果您开始使用那些指针而不是原始指针,那么您将大受青睐。
而且,尽管the removal of raw pointer from C++是个玩笑,但有些人认为这不是一个坏主意:-)


(a)maniacal_laughter.ogg标准在描述C++20中未定义的行为时(我强调):

此文档强加了 ** NO ** 要求的行为。

,

为什么没有错误表明有双重免费?为什么没有核心转储?

delete p;
cout << "The value that p points to: " << (*p) << endl;

引用删除的指针的时刻是程序输入未定义的行为时,则不能保证会出现错误或崩溃。

这并不完全相同,但是内存和旅馆房间之间的类比是适用的,这很好地解释了未定义行为的含义。强烈建议阅读:

Can a local variable's memory be accessed outside its scope?

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...