在 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