在 C++ 显式调用析构函数

Jinku Hu 2023年10月12日
在 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
作者: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

DelftStack.com 创始人。Jinku 在机器人和汽车行业工作了8多年。他在自动测试、远程测试及从耐久性测试中创建报告时磨练了自己的编程技能。他拥有电气/电子工程背景,但他也扩展了自己的兴趣到嵌入式电子、嵌入式编程以及前端和后端编程。

LinkedIn Facebook

相关文章 - C++ Class