#include <iostream>
using namespace std;
namespace GB
{
class Test
{
public:
Test() { cout << "Constructor is executed\n"; }
~Test() {
cout << i << " " << "Destructor is executed\n";
this->i = 7;
}
int i = -1;
};
}
int main()
{
// Test(); // Explicit call to constructor
GB::Test t; // local object
t.i = 6;
t.~Test(); // Explicit call to destructor
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出
Constructor is executed
6 Destructor is executed
6 Destructor is executed
Run Code Online (Sandbox Code Playgroud)
我的问题是:
1)为什么析构函数被调用两次。
2)在析构函数的第一次调用中,成员值从 6 更改为 7 ,在第二次调用中仍然是 6 。
3)我们可以停止析构函数的第二次调用吗(我只想保留手动调用析构函数)。
为什么析构函数被调用两次。
第一个电话来自线路i.~Test();。
第二个调用是当变量i超出范围时(从 返回之前main)自动调用析构函数。
在析构函数的第一次调用中,成员值从 6 更改为 7 ,仍然在第二次调用中变为 6。
这是由未定义的行为引起的。当一个对象的析构函数被调用两次时,你应该期待未定义的行为。当程序进入未定义的行为领域时,不要试图使逻辑有意义。
我们可以停止析构函数的第二次调用吗(我只想手动调用析构函数)。
当变量超出范围时,您不能禁用对自动变量的析构函数的调用。
如果要控制何时调用析构函数,请使用动态内存(通过调用new Test)创建对象并通过调用销毁对象delete。
GB::Test* t = new GB::Test(); // Calls the constructor
t->i = 6;
delete t; // Calls the destructor
Run Code Online (Sandbox Code Playgroud)
即使在这种情况下,显式调用析构函数也几乎总是错误的。
t->~Test(); // Almost always wrong. Don't do it.
Run Code Online (Sandbox Code Playgroud)
请注意,如果您想使用动态内存创建对象,最好使用智能指针。例如
auto t = std::make_unique<GB::Test>(); // Calls the constructor
t->i = 6;
t.reset(); // Calls the destructor
Run Code Online (Sandbox Code Playgroud)
如果t.reset();被忽略,动态分配的对象的析构函数将被调用,并且当t超出范围时内存将被释放。t.reset();允许您控制底层对象何时被删除。