我正在尝试使用C++中的析构函数,以下是我的代码:
#include <iostream>
struct temp
{
~temp() { std::cout << "Hello!" << std::endl; }
};
int main()
{
temp t;
t.~temp();
}
我发现“Hello!”被打印了两次。析构函数的调用不应该在对象被释放后再次被调用吗?还是说有其他概念存在?
(我并不打算在实践中这样做。我只是想理解这里发生了什么。)
我正在尝试使用C++中的析构函数,以下是我的代码:
#include <iostream>
struct temp
{
~temp() { std::cout << "Hello!" << std::endl; }
};
int main()
{
temp t;
t.~temp();
}
发生这种情况是因为您告诉它要发生。自动变量的析构函数在变量超出范围时总是被调用。 您还调用了它。 总共有两次调用。
调用对象的析构函数并不表示不需要再次调用,因为在正常执行中没有必要进行跟踪。
解决方案是永远不手动调用您的析构函数。
调用析构函数并不会 释放 对象。
析构函数的作用是清理对象的内部,然后在析构函数完成后释放对象本身。
和调用两次delete一样,你现在所做的事情是错误的。虽然你可以调用两次delete,但这样做是错误的。
只有极少数情况需要手动调用析构函数,而当前情况不是其中之一。手动调用析构函数主要用于在内存地址上手动构造一个对象(使用placement new),然后需要在不释放内存的情况下析构对象。
class A
{
public:
A() : _closed(false)
{}
~A()
{
close();
}
void close()
{
if (! _closed()) {
// close file handles etc.
}
}
private:
bool _closed
}
你只需要调用析构函数,实际上并没有释放任何内存(它是静态分配的)。如果你使用 new 然后 delete,析构函数只会被调用一次。
类的析构函数可以被调用:
显式地
当使用该类对象显式调用析构函数时,与调用该类的其他成员函数相同。
隐式地
当该类对象超出作用域或使用new操作符创建的对象使用delete操作符进行销毁时。
在您的示例程序中,您两者都做了
int main()
{
temp t;
t.~temp(); //1. Calling destructor explictly using the object `t`
return 0;
} // 2. object `t` goes out of scope. So destructor invoked implictly
这就是你看到析构函数被调用两次的原因。
正如你所想,析构函数将销毁由构造函数创建的资源。因此,不应显式调用析构函数,否则会导致销毁已经被销毁的资源,这可能是致命的。
你实际上不应该调用析构函数。它由运行时支持自动调用。因此,你调用一次,运行时支持会第二次调用。
下面是一些关于析构函数的思考:
虽然可以显式调用析构函数,但不建议这样做,通常它们是隐式调用的。
你不需要显式地调用析构函数,当变量超出作用域时(在return 0;
语句之后),它会自动调用。这就是为什么它会被调用两次,你先调用它,然后系统再调用它。
如果你想要能够自己显式地删除该类的实例,你需要动态分配它:
temp *t = new temp;
// do stuff with t...
delete t; // do not forget this, or the constructor is not being called at all