C++ で明示的にデストラクタを呼び出す

胡金庫 2023年10月12日
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
著者: 胡金庫
胡金庫 avatar 胡金庫 avatar

DelftStack.comの創設者です。Jinku はロボティクスと自動車産業で8年以上働いています。自動テスト、リモートサーバーからのデータ収集、耐久テストからのレポート作成が必要となったとき、彼はコーディングスキルを磨きました。彼は電気/電子工学のバックグラウンドを持っていますが、組み込みエレクトロニクス、組み込みプログラミング、フロントエンド/バックエンドプログラミングへの関心を広げています。

LinkedIn Facebook

関連記事 - C++ Class