堆栈对象的“删除”行为是啥? [复制]

Posted

技术标签:

【中文标题】堆栈对象的“删除”行为是啥? [复制]【英文标题】:What is the behavior of "delete" with stack objects? [duplicate]堆栈对象的“删除”行为是什么? [复制] 【发布时间】:2014-02-28 02:37:06 【问题描述】:
int main()

    Class_Name t;
    Class_Name * p = &t;

    delete p;
    return 0;
  

这段代码在调用 2 个析构函数的情况下可以正常执行吗?删除如何处理堆栈对象?行为是否未定义?

【问题讨论】:

编译器负责一切 你真的,真的不能这样做。只能将 delete 与 new 一起使用。行为是未定义的(见下面的答案),最终它会咬你。现在停止。 【参考方案1】:

您遇到了未定义的行为。

标准 (N3690) 5.3.5[expr.delete]/2

如果操作数具有类类型,则操作数转换为指针 通过调用上述转换函数键入,然后 转换后的操作数用于代替原始操作数 本节的其余部分。 在第一种选择(删除对象)中, delete 的操作数的值可能是空指针值,a 指向由先前的 new 表达式创建的非数组对象的指针,或 一个指向子对象 (1.8) 的指针,表示此类的基类 对象(第 10 条)。如果不是,则行为未定义。 ...

您没有空指针,也没有以前用 new 分配的 Object,因此行为未定义。

注意:即使尝试做

int main()

    Class_Name t;
    t.~Class_Name()
    return 0;

这将是未定义的行为。即使它没有删除,只是因为它显式调用了具有自动存储持续时间的 Object 的析构函数。这意味着析构函数将被调用两次,一次是在显式调用时,第二次是在离开它的作用域时。

标准 12.4[class.dtor]/15

一旦为一个对象调用析构函数,该对象就不再 存在;如果为某个对象调用析构函数,则行为未定义 生命周期已结束的对象 (3.8)。 [ 例子:如果析构函数 对于自动对象被显式调用,并且该块是 随后以通常会调用隐式的方式离开 对象的破坏,行为是未定义的。 —结束示例 ]

大多数时候,尝试做类似的事情会(希望)导致崩溃。使用微不足道的解构器,您可能会(运气不好),但什么也没有发生。

这里有一些术语挑剔:C++ 标准没有讨论堆栈对象和堆对象,它总是分别讨论自动和动态存储持续时间。您也可以在上面的引文中看到。


您应始终遵循一般准则:

对于堆栈分配的对象,不要进行任何显式释放/删除(自动调用析构函数)。 对于每个new,应该有一个对应的delete 对于每个new[],应该有一个对应的delete[] 对于每个malloccalloc 应该有一个对应的free

【讨论】:

第 1 段无关紧要。他正在传递一个指向对象的指针。 @BЈовић 它明确表示只有空指针和指向先前分配有new 的对象的指针是有效的,其他一切都是无效的。因此,指向堆栈上对象的指针对于删除表达式是无效的。 另请注意,该子句中的子对象/基类写得有点混乱,但基本上意味着您可以在指向基类的指针上调用 delete,该指针指向派生类的元素。跨度> @Tribse:但是应该补充一点,要使子对象/基础子句起作用,基础必须具有虚拟析构函数。这是规范中的不同条款要求,但崩溃实际上来自删除,它无法找到对象实际开始的位置。 @JanHudec 是的,我想我应该在评论中添加它。 =)

以上是关于堆栈对象的“删除”行为是啥? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

给定单个参数的子图的行为是啥? [复制]

c#中的行为抽象类和接口是啥? [复制]

在 CSS 中同时使用位置和显示的行为是啥? [复制]

在 PHP 7 中创建类似枚举的行为的推荐方法是啥? [复制]

小对象堆栈存储、严格别名规则和未定义行为

是否缺少删除未定义的行为? [复制]