为什么我们说对象超出范围时调用析构函数?
Why We Say Destructor Call When Object Goes out of Scope?
我了解到当对象超出范围时会调用析构函数,并且析构函数还会删除对象。好的,但是这里发生了什么?
我是显式调用析构函数,如果它删除了对象那么为什么要隐式调用析构函数?即使现在没有对象,因为它已经被显式析构函数调用删除了。对不起,我可能是明确和隐含地错了但是试着理解我的问题。
#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
超出范围的对象会调用其析构函数。这是 C++ 语言标准强制要求的不可更改的保证。您是否事先手动调用了析构函数并不重要;当它超出范围时,将调用析构函数。如果您编写的析构函数被调用两次就会发生坏事,或者如果编译器插入析构函数代码的额外行为不想被调用两次,那么坏事就会发生。
这是您永远不应手动调用析构函数的众多原因之一。
您的对象不包含任何指针。它在调用时不会释放析构函数中的任何对象,因此在多次调用时不会造成任何伤害。
如果析构函数删除指针并且那些指针没有设置为0,这在析构函数中很常见,那么第二次调用析构函数将是有害的,因为它会导致内存错误。
析构函数不是删除对象,而是析构它。
并且除非对象是 POD 类型(基本上,你
可以在 C 中定义),销毁一个已经销毁的对象是
未定义的行为。由于所有变量都会自动具有
他们的析构函数在他们的生命周期结束时调用,你应该
永远不要明确地调用它们的析构函数。同样,如果你
使用 new
的非放置形式创建了对象:
显式调用析构函数不会释放内存;你
应该使用 delete
,它调用析构函数然后释放
记忆。
你唯一应该显式调用析构函数的时间是
您已使用 placement new 来构造对象,以便
单独分配和初始化。今天,这样的技术
真的应该算是高级了,难得一见
程序员需要它们。
您提供的 class 不管理任何数据,因此其析构函数没有任何对象可释放。这就是为什么您可以两次调用析构函数而不会产生任何后果的原因。这是一个无法通过相同测试的示例 class:
#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
分配 space,析构函数运行 delete
以释放 space。 ~A()
在 main()
中被调用了两次(首先是显式调用,然后是隐式调用),这可以理解地导致内存错误。
查看此 link 了解有关析构函数如何工作的更多信息:
https://isocpp.org/wiki/faq/dtors
我了解到当对象超出范围时会调用析构函数,并且析构函数还会删除对象。好的,但是这里发生了什么?
我是显式调用析构函数,如果它删除了对象那么为什么要隐式调用析构函数?即使现在没有对象,因为它已经被显式析构函数调用删除了。对不起,我可能是明确和隐含地错了但是试着理解我的问题。
#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
超出范围的对象会调用其析构函数。这是 C++ 语言标准强制要求的不可更改的保证。您是否事先手动调用了析构函数并不重要;当它超出范围时,将调用析构函数。如果您编写的析构函数被调用两次就会发生坏事,或者如果编译器插入析构函数代码的额外行为不想被调用两次,那么坏事就会发生。
这是您永远不应手动调用析构函数的众多原因之一。
您的对象不包含任何指针。它在调用时不会释放析构函数中的任何对象,因此在多次调用时不会造成任何伤害。 如果析构函数删除指针并且那些指针没有设置为0,这在析构函数中很常见,那么第二次调用析构函数将是有害的,因为它会导致内存错误。
析构函数不是删除对象,而是析构它。
并且除非对象是 POD 类型(基本上,你
可以在 C 中定义),销毁一个已经销毁的对象是
未定义的行为。由于所有变量都会自动具有
他们的析构函数在他们的生命周期结束时调用,你应该
永远不要明确地调用它们的析构函数。同样,如果你
使用 new
的非放置形式创建了对象:
显式调用析构函数不会释放内存;你
应该使用 delete
,它调用析构函数然后释放
记忆。
你唯一应该显式调用析构函数的时间是 您已使用 placement new 来构造对象,以便 单独分配和初始化。今天,这样的技术 真的应该算是高级了,难得一见 程序员需要它们。
您提供的 class 不管理任何数据,因此其析构函数没有任何对象可释放。这就是为什么您可以两次调用析构函数而不会产生任何后果的原因。这是一个无法通过相同测试的示例 class:
#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
分配 space,析构函数运行 delete
以释放 space。 ~A()
在 main()
中被调用了两次(首先是显式调用,然后是隐式调用),这可以理解地导致内存错误。
查看此 link 了解有关析构函数如何工作的更多信息: https://isocpp.org/wiki/faq/dtors