デストラクタ詳解
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 24/104。
デストラクタは、オブジェクトが破棄されるときに自動的に実行される特別なメンバ関数です。その主な役割は、動的に割り当てられたメモリ、ファイルハンドル、ネットワーク接続など、オブジェクトがその生存期間中に取得したリソースを解放することです。
デストラクタはクラスと同じ名前を持ち、先頭にチルダ ~ が付加されます。引数は取らず、戻り値の型もありません:
class FileHandler {
std::string filename;
int* buffer;
public:
FileHandler(std::string name, size_t size)
: filename(name), buffer(new int[size]) {
std::cout << "Opening " << filename << "\n";
}
~FileHandler() {
delete[] buffer;
std::cout << "Closing " << filename << "\n";
}
};デストラクタは、次のような状況で自動的に呼び出されます:
- スタックオブジェクトがスコープ外になる
- ヒープに割り当てられたオブジェクトに対して
deleteが呼び出される - 一時オブジェクトの寿命が終了する
void example() {
FileHandler f1("data.txt", 100); // コンストラクタが呼び出されます
FileHandler* f2 = new FileHandler("log.txt", 50);
delete f2; // f2 のデストラクタが呼び出されます
} // f1 のデストラクタが呼び出されます(スコープ外になるため)コンストラクタとは異なり、クラスはデストラクタを1つしか持つことができません。オーバーロードすることはできません。
デストラクタを定義しない場合、コンパイラは特別な処理を行わないデフォルトのデストラクタを生成します。これは単に各メンバを破棄するだけのものです。リソースを管理するクラスでは、メモリリークを防ぐために独自のデストラクタを記述する必要があります。
チャレンジ
簡単アクティブなユーザーセッションを追跡し、オブジェクトが破棄される際(スコープ外に出るか、明示的に削除されるかに関わらず)にデストラクタがどのようにリソースを自動的にクリーンアップするかを実演するセッションマネージャーを構築しましょう。
コードを整理するために2つのファイルを作成します:
Session.h: 動的に割り当てられたデータを持つアクティブなユーザーセッションを表すSessionクラスを定義します。クラスには以下のものを含める必要があります:- プライベートメンバ:
username(string)、sessionId(int)、ユーザーのアクションを追跡するactivityLogという名前の整数配列へのポインタ、および配列サイズのためのlogSize - ユーザー名、セッションID、ログサイズを受け取るコンストラクタ。ヒープ上にアクティビティログ配列を割り当て、すべての要素を 0 に初期化し、
"Session <sessionId> started for <username>"と出力する必要があります - 割り当てられたメモリを解放し、
"Session <sessionId> ended for <username>"と出力するデストラクタ - アクティビティコードを次に利用可能なスロットに格納する
logActivity(int activityCode)メソッド(内部で現在の位置を追跡します) - これまでに記録されたアクティビティの数を返す
getActivityCount()メソッド - ユーザー名を返す
getUsername()メソッド
- プライベートメンバ:
main.cpp: さまざまなシナリオにおけるデストラクタの動作を実演します。入力からユーザー名とログサイズを読み取り(それぞれ別の行)、以下の処理を行います:- 波括弧
{ }を使用してスコープブロックを作成し、その中で入力されたユーザー名、セッションID101、および入力されたログサイズを使用して、スタックに割り当てられたSessionを作成します。コード1と2の2つのアクティビティをログに記録し、"Stack session activities: <count>"と出力します。ブロックが終了すると、デストラクタが自動的に実行されるはずです。 - ブロックの後に、
"Stack session destroyed"と出力します。 newを使用して、ユーザー名"Guest"、セッションID202、ログサイズ3でヒープに割り当てられたSessionを作成します。コード5のアクティビティを1つログに記録し、"Heap session activities: <count>"と出力してから、明示的にdeleteします。- 削除後に、
"Heap session destroyed"と出力します。
- 波括弧
このチャレンジでは、デストラクタが呼び出される2つの主な方法を示しています。スタックオブジェクトがスコープを抜けるときに自動的に呼び出される方法と、ヒープオブジェクトを削除するときに手動で呼び出される方法です。どちらの経路でも、メモリリークを防ぐために動的に割り当てられたアクティビティログを適切に解放する必要があります。
main.cpp で #include "Session.h" を使用してヘッダーファイルをインクルードしてください。
チートシート
デストラクタは、オブジェクトが破棄されるときに自動的に実行される特別なメンバ関数です。動的に割り当てられたメモリ、ファイルハンドル、ネットワーク接続などのリソースを解放します。
デストラクタはクラスと同じ名前を持ち、先頭にチルダ ~ が付きます。引数は取らず、戻り値の型もありません:
class FileHandler {
std::string filename;
int* buffer;
public:
FileHandler(std::string name, size_t size)
: filename(name), buffer(new int[size]) {
std::cout << "Opening " << filename << "\n";
}
~FileHandler() {
delete[] buffer;
std::cout << "Closing " << filename << "\n";
}
};デストラクタは、次の場合に自動的に呼び出されます:
- スタックオブジェクトがスコープ外になったとき
- ヒープに割り当てられたオブジェクトに対して
deleteが呼び出されたとき - 一時オブジェクトの寿命が終了したとき
void example() {
FileHandler f1("data.txt", 100); // コンストラクタが呼び出される
FileHandler* f2 = new FileHandler("log.txt", 50);
delete f2; // f2 のデストラクタが呼び出される
} // f1 のデストラクタが呼び出される(スコープ外になるため)クラスは**1つのデストラクタ**しか持つことができません(オーバーロードは不可)。デストラクタを定義しない場合、コンパイラがデフォルトのデストラクタを生成します。リソースを管理するクラスでは、メモリリークを防ぐために独自のデストラクタを記述する必要があります。
自分で試してみよう
#include <iostream>
#include <string>
#include "Session.h"
using namespace std;
int main() {
// 入力を読み込む
string username;
int logSize;
getline(cin, username);
cin >> logSize;
// TODO: 波括弧 { } を使用してスコープブロックを作成する
// ブロック内:
// - 入力された username、セッションID 101、および入力された logSize を使用して、スタック割り当ての Session を作成する
// - コード 1 と 2 の2つのアクティビティをログに記録する
// - "Stack session activities: <count>" を出力する
// ブロックが終了すると、デストラクタが自動的に実行される
// TODO: ブロックの後で、"Stack session destroyed" を出力する
// TODO: new を使用してヒープ割り当ての Session を作成する
// - Username: "Guest"、セッションID: 202、log size: 3
// - コード 5 のアクティビティを1つログに記録する
// - "Heap session activities: <count>" を出力する
// - セッションを delete する
// TODO: 削除後、"Heap session destroyed" を出力する
return 0;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタ引数付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ詳解Rule of Three / Five / Zeroまとめ - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () 演算子のオーバーロード型変換演算子まとめ:Matrix クラス