int main()
{
Class_Name t;
Class_Name * p = &t;
delete p;
return 0;
}
这个代码执行正常,调用了2个析构函数? delete如何使用堆栈对象?行为未定义吗?
答案 0 :(得分:12)
您遇到了未定义的行为。
标准(N3690)5.3.5 [expr.delete]
/ 2
如果操作数具有类类型,则操作数将转换为指针 通过调用上面提到的转换函数来键入 转换后的操作数用于代替原始操作数 本节的其余部分。 在第一个替代(删除对象)中, delete的操作数的值可以是空指针值,a 指向由前一个new-expression创建的非数组对象的指针,或 指向表示这种类的基类的子对象(1.8)的指针 对象(第10条)。如果不是,则行为未定义 ... 强>
您没有空指针,也没有先前使用new分配的Object,因此行为未定义。
注意:即使在尝试
时也是如此int main()
{
Class_Name t;
t.~Class_Name()
return 0;
}
这将是未定义的行为。即使它没有删除,只是因为它显式调用具有自动存储持续时间的Object的析构函数。这意味着析构函数将被调用两次,一次是在显式调用时,第二次是在离开它的范围时。
标准12.4 [class.dtor]
/ 15
一旦为对象调用析构函数,该对象就不再存在 存在;如果为a调用析构函数,则行为未定义 生命周期结束的对象(3.8)。 [示例:如果是析构函数 显式调用自动对象,块为 随后以通常会隐含的方式离开 破坏对象,行为未定义。 - 示例]
大多数时候尝试做这样的事情(希望)会导致崩溃。通过一个简单的解构器,你可能会有(坏)运气,但没有任何反应。
这里的术语很少:C ++标准没有讨论堆栈与堆对象,它总是分别讨论自动存储持续时间和动态存储持续时间。您也可以在上面的引文中看到。
您应始终遵循一般准则:
new
,应该有相应的delete
new[]
,应该有相应的delete[]
malloc
或calloc
,应该有相应的free