C++ で明示的にデストラクタを呼び出す
この記事では、C++ でデストラクタを明示的に呼び出す方法のいくつかの方法について説明します。
obj.~ClassName()
表記を使用して、デストラクタ関数を明示的に呼び出する
デストラクタは、オブジェクトが自動的にスコープ外になるか、ユーザーによる明示的な呼び出しによって削除されたときに実行される特別な関数です。これらの関数は通常、特定のオブジェクトによって使用されているリソースを解放するために使用されることに注意してください。デストラクタはメンバー関数として明示的に呼び出すことができますが、これを行う必要はありません。ほとんどの場合、クラスデータメンバーが動的に割り当てられると、リソースが二重に解放される可能性があります。後者のシナリオでは、通常、プログラムが異常終了します。
次の例では、MyClass
という定義済みのクラスを示します。このクラスには、2つのコンストラクターと 1つの組み込みメソッドがあり、データメンバーの値のみを取得します。デストラクタも定義されており、コンストラクタを使用すると、対応するメッセージが cout
ストリームに出力され、動作の調査が容易になります。
次のサンプルコードは 2つのデストラクタメッセージを出力します。1つは明示的なユーザー呼び出しによってトリガーされ、もう 1つはプログラムの終了時に自動的に呼び出されます。ただし、コンストラクターで 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
考慮すべきもう 1つのケースは、クラスオブジェクトが 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