堆栈对象“删除”的行为是什么?

时间:2014-02-04 06:36:44

标签: c++ memory memory-management stack

int main()
{
    Class_Name t;
    Class_Name * p = &t;

    delete p;
    return 0;
}  

这个代码执行正常,调用了2个析构函数? delete如何使用堆栈对象?行为未定义吗?

1 个答案:

答案 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[]
  • 对于每个malloccalloc,应该有相应的free