堆栈对象的“删除”行为是啥? [复制]
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[]
对于每个malloc
或calloc
应该有一个对应的free
【讨论】:
第 1 段无关紧要。他正在传递一个指向对象的指针。 @BЈовић 它明确表示只有空指针和指向先前分配有new
的对象的指针是有效的,其他一切都是无效的。因此,指向堆栈上对象的指针对于删除表达式是无效的。
另请注意,该子句中的子对象/基类写得有点混乱,但基本上意味着您可以在指向基类的指针上调用 delete,该指针指向派生类的元素。跨度>
@Tribse:但是应该补充一点,要使子对象/基础子句起作用,基础必须具有虚拟析构函数。这是规范中的不同条款要求,但崩溃实际上来自删除,它无法找到对象实际开始的位置。
@JanHudec 是的,我想我应该在评论中添加它。 =)以上是关于堆栈对象的“删除”行为是啥? [复制]的主要内容,如果未能解决你的问题,请参考以下文章