8

我遇到了我的第一个编译器,它更改了传递给 ::delete 的左值,但没有将左值清零。即以下情况属实:

 Foo * p = new Foo();
 Foo * q = p;
 assert(p != 0);
 assert(p == q);
 ::delete p;
 assert(p != q);
 assert(p != 0);

请注意,删除操作后 p 不为零,并且它已从旧值更改。一位同事告诉我,在他使用一些将 p 更改为 0xFFFFFFFF 的大型机 C++ 编译器以及将 p 更改为 0 的其他编译器的经验中,这并不罕见。

C++ 标准中的什么地方说允许编译器执行此操作?

通过StackOverflow搜索,我发现了这个问题:为什么不删除将指针设置为NULL?其中有一个答案提到了Bjarne Stroustrup 的回应,其中包括以下声明:

C++ 明确允许删除的实现将左值操作数清零,我曾希望实现能够做到这一点,但这个想法似乎并没有在实现者中流行。

我已经阅读并重新阅读了最终委员会草案 C++0x 标准的第 5.3.5 和 12.5 节,但我没有看到“显式”部分。我只是在查看标准的错误部分吗?或者这些部分是否存在逻辑链,但我只是没有正确连接在一起。

我不再拥有 Annotated C++ Reference Manual 的副本。编译器可以在ARM中执行此操作吗?

[编辑:将部分参考从 3.5.3 更正为 5.3.5。我还添加了一个有趣的悖论作为 Henk 断言 p 在删除后未定义的对立面。]

如果将 p 初始化为 null,则会出现一个有趣的悖论。

 Foo * p = 0;
 Foo * q = p;
 assert(p == 0);
 assert(p == q);
 ::delete p;
 assert(p == q);
 assert(p == 0);

但是,在这种情况下,该行为是有据可查的。当 delete 得到一个空指针时,它应该什么都不做,所以 p 保持不变。

4

1 回答 1

8

它可能不是那么明确。在 5.3.5/7 中,它说删除表达式将调用一个释放函数。然后在 3.7.3.2/4 中,它说使用已被释放的指针是未定义的。由于指针的值在释放后无法使用,那么指针是保持值还是由实现改变值都没有区别。

5.3.5/7

删除表达式将调用释放函数(3.7.3.2)。

3.7.3.2/4

如果标准库中的释放函数的参数是一个不是空指针值的指针(4.10),则释放函数将释放指针所引用的存储空间,使所有引用该指针的任何部分的指针无效。释放的存储空间。使用无效指针值(包括将其传递给释放函数)的效果是 undefined

参考文献来自现行标准。在即将发布的标准 5.3.5/7 中已经改写:

C++0x FD 5.3.5/7

如果 delete-expression 的操作数的值不是空指针值,则 delete-expression 将调用释放函数 (3.7.4.2)。否则,未指定是否将调用释放函数。[注意:无论对象的析构函数还是数组的某些元素是否抛出异常,都会调用释放函数。——尾注]

于 2010-08-02T22:05:13.267 回答