我想知道如果我们删除在堆栈上声明的对象两次会发生什么。为了测试这个,我写了这个简单的程序:
#include <iostream>
using namespace std;
class A {
public:
A() {}
virtual ~A() {
cout << "test" << endl;
}
};
int main()
{
A a;
a.~A();
}
我实际上是在期待分段错误,因为我在代码中明确地删除了A,并且当它超出范围时会再次被删除,但是令人惊讶的是程序会产生以下输出:
“测试”
“测试”
有人可以解释为什么这段代码有效吗?
答案 0 :(得分:4)
有三个原因:
析构函数不会解除分配对象,它会执行您认为有用的任何清理操作(默认情况下,不执行任何操作)。它在变量超出范围或被明确删除之前被隐式调用,但您也可以自由调用它。
解除分配通常不会导致内存停止存在也不会无法访问。它被标记为可重用。 (无论如何,双重释放应该引发内存管理错误情况。)
最后但并非最不重要的是,堆栈上分配的对象未被释放(当您退出该函数时,堆栈指针移动到前一帧,保持堆栈不变)。
答案 1 :(得分:2)
你的程序有不明确的行为,所以它可能很容易被分割,或者偷走我的车,或者进入太空开始一个令人兴奋的新的女同性恋鹦鹉群。
但是,在实践中,您可以解释您所见证的行为。调用析构函数不会“删除”一个对象;它只是调用析构函数。析构函数调用是对象删除的一部分;你的只是打印到标准输出,所以这里没有什么可以触发内存访问违规。
更一般地说,“期待分段错误”总是愚蠢。
但是,如果您实际尝试使用delete
删除对象,如果您的程序在运行时没有崩溃,我会感到惊讶。
答案 2 :(得分:0)
你打电话给一个破坏者。这不会删除变量,它只是调用析构函数。变量将在函数出口处从堆栈中删除。
答案 3 :(得分:0)
顾名思义,a
是&#34; 变量,具有自动生命周期&#34;这意味着你不能过早地结束它的生命。它与创建的范围绑定在一起。您只需手动调用析构函数,这只是另一种打印内容的方法。然后,运行时会在实际销毁和生命周期结束时再次自动调用它。通过定义自动管理对象的范围,您可以稍微控制自动管理对象的生命周期:
int main()
{
{
A a;
} // 'a' is destroyed here.
} // instead of here.