在 C++ 顯式呼叫解構函式
Jinku Hu
2023年10月12日
本文將介紹幾種如何在 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