我了解到当对象超出范围并且析构函数删除对象时会调用析构函数。好的,但是这里发生了什么?
我明确地调用了析构函数,如果它删除了对象,那么为什么隐式调用析构函数呢?即使现在没有对象,因为它已经被明确的析构函数调用删除了。对不起,我可能是明确而含蓄的错误但是试着理解我的问题。
#include <iostream>
using namespace std;
class A{
public:
A(){
cout << "Constructor" << endl;
}
~A(){
cout << "Destructor" << endl;
}
};
int main(){
A obj;
obj.~A();
cout << "End" << endl;
}
现在
obj.~A();
上面的行删除了该对象。然后为什么再次调用析构函数?即使没有任何对象。
输出:
Constructor
Destructor
End
Destructor
答案 0 :(得分:4)
超出范围的对象的析构函数被调用。这是C ++语言标准强制要求的不可改变的保证。如果您事先手动调用析构函数并不重要;当它超出范围时,将调用析构函数。如果你已经编写了析构函数,如果它被调用两次就会发生坏事,或者如果编译器插入析构函数代码中的额外行为不想被调用两次,那么坏事就会发生发生。
这是您不应该手动调用析构函数的众多原因之一。
答案 1 :(得分:1)
析构函数不删除对象,它会破坏它。
除非对象是POD类型(基本上,你的东西
可以在C)中定义,破坏已被破坏的对象
未定义的行为。由于所有变量都会自动拥有
他们应该在他们的生命结束时召唤他们的析构者
从不在它们上显式调用析构函数。同样,如果你
使用非展示形式的new
创建了对象:
显式调用析构函数不会释放内存;您
应该使用delete
,它调用析构函数然后释放
记忆。
你应该明确调用析构函数的时间是 你已经使用了placement new来构造对象,以便 单独分配和初始化。今天,这样的技术 应该被认为是先进的,而且很少见 程序员需要它们。
答案 2 :(得分:1)
您提供的课程没有管理任何数据,因此其析构函数没有任何可以释放的对象。这就是为什么你能够两次调用析构函数而没有任何后果的原因。这是一个未通过相同测试的示例类:
#include <iostream>
class A {
public:
A() {
std::cout << "constructing..." << '\n';
val = new int;
}
~A() {
std::cout << "destructing..." << '\n';
delete val;
}
private:
int* val;
};
int main() {
A obj;
obj.~A();
std::cout << "End" << '\n';
return 0;
}
构造函数在堆上为val
分配空间,析构函数运行delete
以释放该空间。在~A()
中调用main()
两次(首先是显式的,然后是隐式的),这可以理解地导致内存错误。
查看此链接以获取有关析构函数如何工作的更多信息: https://isocpp.org/wiki/faq/dtors
答案 3 :(得分:0)
您的对象不包含任何指针。它在调用时不释放析构函数中的任何对象,因此在多次调用时不会造成任何损害。 如果析构函数删除指针并且那些指针未设置为0(这在析构函数中通常是这种情况),那么析构函数的第二次调用将是有害的,因为它会导致内存错误。