【问题标题】:Why (&this != nullptr) after deletion?为什么 (&this != nullptr) 删除后?
【发布时间】:2015-11-24 02:39:50
【问题描述】:

我有一堂课:

class A
{
public:
    void foo(void)
    {
        // equals to syntactically incorrect (&this == nullptr)
        if (*(void**)this == nullptr)
            return;
        ...
    }
};

我是这样使用的:

A * a = new A;
...

delete a;
...

a->foo();

为什么true 仅适用于release 版本?如果我切换到 debug 版本,我通常会得到类似 0xFEEFEEFE 的信息。

编辑

好的,伙计们。你说的完全正确,我知道这一点。 未定义的行为是标准未指定的行为。 这就是每个平台都以自己的方式实现(但实现)的内容。

这个问题的目的是了解它是如何在 Windows 中实现的。此代码始终正常工作(“始终正常”意味着:在所有版本的 Windows(从 xp 开始)上,使用任何编译器调用该方法并且该语句为真))。就我而言,我想知道如果 在 Windows 中删除对象通常会发生什么。

附: 我应该在 wasm.ru 上问这个问题。对不起。

【问题讨论】:

  • 未定义的行为是未定义的,不要做导致它的事情。
  • 不,*(void**)this 等于 &this
  • a->foo() 调用未定义的行为,因此任何事情都可能发生。
  • in this other question 的主题相同。
  • 唯一的中途“正确”方法是按原样测试this,而不是在类型案例之后取消引用它,但即便如此,它也只是有点帮助,如果有的话 i>(我参与了一个项目,我们实际上这样做的原因除了几年前放支票的那个人之外没有人知道,但也没有人有动力删除它们)。该标准明确规定,在删除 this 后,您不得对它进行任何操作(包括查看它,如果您是迂腐的!)因此仅成员调用就已经深入 UB 领域,此后发生的任何检查都只是一个在黑暗中拍摄...

标签: c++ oop debugging


【解决方案1】:

为什么这是真的?未指定删除后指针的值是什么。在删除指针后,实现不需要将指针设置为空。真的this 不应该为空,除非你已经在疯狂的小镇。

编辑:OP 显示更多代码后:

A * a = new A;
...

delete a;
...

a->foo();

是的,那条线a->foo();?这是获得未定义行为的最可靠方法。

【讨论】:

  • 为什么投反对票?这是正确的答案。它甚至警告不要去疯狂的小镇。
  • 要添加到这个正确答案,取消引用 this 作为有效性检查也是调用 UB 的可靠方法。请注意,*(void**) 不仅将this 类型转换为指向空指针的指针,而且还取消引用该指针。如果this 有效,那是废话,如果不是,则作为“安全检查”更废话。
  • 过度使用安全检查通常会导致代码变慢且不安全 - 真实的故事。
【解决方案2】:

您假设 delete 会将 nullptr 放入保存要删除的指针的变量中。这不是真的,delete 不是那样做的。

为什么该条件仅适用于发布版本?如果我切换到调试版本,我通常会得到类似 0xFEEFEEFE 的信息。

在 Windows 下调用delete a; 时,CRT 库会将指针下的内存标记为已释放。在调试模式下,它另外将 0xFEEFEEFE 值放入此内存区域,这意味着 freefree。当使用释放的内存时,这使得在调试情况下更容易找到。在发布模式下,CRT 不会在删除后放置此值。

如果 (*(void**)this == nullptr)

在这种情况下,this 指针被声明为class-type * this,因此将其转换为 (void**) 是完全错误的。

a->foo();

这是错误的,删除后你不应该使用a - 它会导致UB

【讨论】:

  • 好的,那零这个呢。如果 CRT 没有输入值0xFEEFEFFF,那么它可能会输入零?为什么调用a->foo() 会起到作用?为什么内存中 foo 的代码仍然引用到已删除的对象?或者它可能没有被引用。但是为什么a->foo() 的电话把我变成了 foo 的身体呢?
  • 它不会将 0xFEEEFEEE 或 NULL 放入您的 a 变量中,而是放入 a 指向的内存中。你可以读到这样:stackoverflow.com/questions/16585562/… this 主要是作为隐藏方法参数实现的,所以foo 方法调用中的this 将等于a 中的地址,即使它是一个悬空指针。所以你调用会成功,你会看到这与删除之前的指针相同(即使这是无效的指针),但你的 foo 方法将适用于保留在已释放内存区域中的数据......
  • ...这个内存区域可能和之前长时间调用delete之前一样。但是其他一些分配可能会利用这个区域并在那里放置一些新数据。这是 UB,这是应该避免的。
  • 在那个线程中你建议我说this 不是一个变量。它是一种表达方式。那么,可能会有一些 thistable 吗? CRT“跟踪”对象的this 多长时间?我试图删除我的对象,分配很多东西,写它,释放它;但同样,如果我将其称为已删除的a->foo(),我的结果为零。我了解a 指向的内存已更改。但是,this 是从哪里获取并传递给 foo 的?
  • @JohnSmith this 提供的更像:a->foo(a);,因此它作为参数传递,这也意味着它不会与您的类实例一起存储。没有这个表。 CRT 不会显式跟踪此指针,在您的情况下,您的类实例的 thisa 变量,并且它的生命周期在 main 结束时结束。 I have a zero-this - 我试过了,在调试和发布时,删除后永远不会为零 - 至少在 VS2015 下。
猜你喜欢
  • 2015-10-15
  • 2015-11-24
  • 1970-01-01
  • 1970-01-01
  • 2012-10-17
  • 1970-01-01
  • 2018-10-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多