在 C++ 显式调用析构函数
本文将介绍几种如何在 C++ 中显式调用析构函数的方法。
使用 obj.~ClassName()
表示法明确调用析构函数
析构函数是特殊函数,当对象自动超出范围或由用户显式调用删除时,析构函数将执行。注意,这些函数通常用于释放给定对象使用的资源。即使可以将析构函数显式调用为成员函数,也无需这样做。在大多数情况下,动态分配类数据成员会导致资源的双重释放。后一种情况通常会导致程序异常终止。
在下面的示例中,我们演示定义的类-MyClass
,该类具有两个构造函数和一个内置方法来检索唯一数据成员的值。还定义了析构函数,并使用构造函数将析构函数将相应的消息打印到 cout
流中,以使我们更容易调查行为。
请注意,以下示例代码显示了两个析构函数消息,其中一个由显式用户调用触发,而另一个则在程序退出时自动调用。虽然,如果在构造函数中为 MyClass
数据成员分配了 new
运算符,则此示例将导致程序异常终止-可能是双重错误。
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string;
class MyClass {
public:
explicit MyClass(string s):
str(std::move(s)) { cout << "Constructor 1 executed\n"; }
MyClass(const MyClass &s):
str(string(s.str)) { cout << "Constructor 2 executed\n"; }
~MyClass() { cout << "Destructor executed\n"; }
string& getString() { return str; };
private:
string str;
};
int main()
{
MyClass str1("Hello There! ");
cout << endl;
cout << "str1: " << str1.getString() << endl;
cout << endl;
str1.~MyClass();
return EXIT_SUCCESS;
}
输出:
Constructor 1 executed
str1: Hello There!
Destructor executed
Destructor executed
另外,我们可以看到以下版本的代码触发了相同数量的构造函数/析构函数,这实际上是该概念背后的思想。因此,即使最后一个示例可以正常工作,也不建议显式调用析构函数。
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string;
class MyClass {
public:
explicit MyClass(string s):
str(std::move(s)) { cout << "Constructor 1 executed\n"; }
MyClass(const MyClass &s):
str(string(s.str)) { cout << "Constructor 2 executed\n"; }
~MyClass() { cout << "Destructor executed\n"; }
string& getString() { return str; };
private:
string str;
};
int main()
{
MyClass str1("Hello There! ");
MyClass str2(str1);
cout << endl;
cout << "str2: " << str2.getString() << endl;
cout << endl;
return EXIT_SUCCESS;
}
输出:
Constructor 1 executed
Constructor 2 executed
str2: Hello There!
Destructor executed
Destructor executed
要考虑的另一种情况是,用 new
运算符分配了类对象,并且在程序退出之前,在同一对象上调用了 delete
。请注意,在执行描述符函数后,将打印最后一个 cout
语句,这意味着在调用 delete
运算符时会调用该描述符。
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string;
class MyClass {
public:
explicit MyClass(string s):
str(std::move(s)) { cout << "Constructor 1 executed\n"; }
MyClass(const MyClass &s):
str(string(s.str)) { cout << "Constructor 2 executed\n"; }
~MyClass() { cout << "Destructor executed\n"; }
string& getString() { return str; };
string* getStringAddr() { return &str; };
private:
string str;
};
int main()
{
auto *str4 = new MyClass("Hello There! ");
cout << endl;
cout << "str4: " << str4->getString() << endl;
cout << endl;
delete str4;
cout << "exiting" << endl;
return EXIT_SUCCESS;
}
输出:
Constructor 1 executed
str4: Hello There!
Destructor executed
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn