デストラクタ

デストラクタ(英: destructor)は、オブジェクト指向プログラミング言語でオブジェクト(インスタンス)を削除する際に呼び出されて後処理などを行なう関数あるいはメソッドのこと。C++やDelphi、Rustにおいてサポートされている。デストラクタは確実かつ安全なリソース管理を実現するための重要な役割を担う。

日本語では「解体子」という直訳が割り当てられることもあるが、ほとんど使用されることはない。

なお、本項では類似概念であるファイナライザについても合わせて述べる。

C++

デストラクタはオブジェクトの寿命が終了するタイミング、メモリ領域が破棄される直前に自動的に呼び出される。具体的には自動変数(ローカル変数)ならばその変数が属するブロックを抜けた直後、静的オブジェクトならばプログラム終了直前、new演算子で生成したオブジェクトならばdelete演算子が適用された時である。主にコンストラクタで確保したリソースを解放するための処理が記述される。

派生クラスの場合は、まず派生クラスのデストラクタが呼ばれて派生クラスによる追加部分が解体されてから、基底クラスのデストラクタが順次呼ばれることでオブジェクトが解体される。基底クラスのポインタで派生クラスのインスタンスをポリモーフィックに利用する場合は、基底クラスのデストラクタを仮想関数にしなければならない(仮想デストラクタ)。これはポインタが参照するインスタンスをdeleteする際に呼び出されるデストラクタがポインタの型で決定されるため、基底クラスのデストラクタが仮想でない場合は、基底クラスのデストラクタだけが呼ばれて派生クラスのデストラクタが呼ばれないためである。基底クラスが仮想デストラクタを持っていれば、実際のインスタンスに応じて派生クラスのデストラクタが正しく呼び出される。ただしこのメカニズムは一般的な仮想関数と同様に仮想関数テーブルを経由して実現されるものであるため、デストラクタを仮想にするとオブジェクトのメモリ上のサイズが多少増加し、また仮想関数テーブルを経由することで呼び出しのオーバーヘッドが多少増えることになる。

自動変数のデストラクタは、例外でブロックを脱出した際にも呼び出される。そのため、コンストラクタでリソースを確保し、デストラクタでリソースを解放するクラスを自動変数として生成することで、ブロック中のどこから例外が投げられてもリソースの解放が確実に行われる。このイディオムをRAII (Resource Acquisition Is Initialization) という。

デストラクタは例外を投げるべきではない。先に述べたようにデストラクタは例外伝播中にも呼ばれる可能性があるが、その時にデストラクタがさらに例外を投げると二重例外となり、プログラムの強制終了を招くからである。

デストラクタは、プログラマが定義しない場合にC++コンパイラが暗黙に生成するメンバー関数のうちの一つである。暗黙のデストラクタの仕様は「中身が空」で「非仮想」となっている。

デストラクタの名前は、クラス名の前に~記号(チルダ、ティルダ)を付けたものと決められている。

下記の例では、main関数を抜けるときにMyClass型の自動変数objが破棄されることによって、デストラクタ~MyClass()が自動的に呼ばれる。

#include   class MyClass { public:     // デフォルトコンストラクタ。     MyClass() { std::cout << "MyClass() is called." << std::endl; }     // デストラクタ。     ~MyClass() { std::cout << "~MyClass() is called." << std::endl; } };  int main() {     std::cout << "main() function started." << std::endl;     MyClass obj; // 関数ブロックを抜けると破棄される。     std::cout << "main() function finished." << std::endl; } 

例えばnew演算子で動的に生成した別のオブジェクト(動的に確保したメモリ領域)へのポインタや、オープンしたファイルのハンドルなどをクラスのメンバー変数として保持しておき、delete演算子による削除(メモリ領域の解放)やファイルのクローズといった後始末用の処理をデストラクタに記述することで、クラスオブジェクトの寿命が尽きたときに後始末を確実に自動実行させることができる。

ファイナライザ

ファイナライザ (finalizer) は、ガベージコレクタを持つ言語において不要オブジェクトが回収される前に自動的に呼び出されるメソッドである。

JavaRubyなどに存在する。C++/CLIにはデストラクタとファイナライザの両方が存在する。C#にはファイナライザのみが存在するが、構文がC++のデストラクタに酷似しており、かつては「デストラクタ」と呼ばれていた。

デストラクタと違い、ファイナライザはオブジェクトが不要になってもすぐには呼ばれるとは限らない。不要になってから実際に回収されるまでの間に、いつか呼ばれるというだけである。それは不要になった直後かもしれないし、遙か後になるかもしれない。さらにはメモリに十分な余裕があれば、オブジェクトが回収されずファイナライザが永遠に呼ばれないということさえありうる。.NET Frameworkの場合はアプリケーションの終了時にファイナライザが呼ばれるが、一般的にはプロセス終了時ですらファイナライザが呼ばれるかどうかは不定である。

このようにいつ呼び出されるかわからない、呼ばれるかどうかすらわからないメソッドのため、確実に実行されなければならないような処理は一般的にファイナライザに任せることはできない。したがって、「ファイナライザによるRAII」は誤りである。ファイナライザで行えることは極めて限定されており、「リソースを解放し忘れていないか確認し、解放し忘れていれば解放する」というような最終防壁としての利用法がせいぜいである。リソースは不要になった時点で適切に解放されているべきであり、ファイナライザのチェックは保険に過ぎない。解放し忘れは本来はバグで、ファイナライザに頼る設計をしてはいけない。ファイナライザを誤って実装すると、脆弱性が生じることもある。

以上のような不確実性に加え、ファイナライザの利用はガベージコレクタの性能を低下させることもあり、積極的に利用されるものではない。ファイナライザを持つオブジェクトはファイナライザ管理リストに登録されるため、ファイナライザを持たないオブジェクトと比べてオーバーヘッドも増える。業務サーバーのような、少々のバグがあっても動き続けていなければ困るようなアプリケーションでは用いられることもある。

Java 9ではファイナライザが非推奨となった。

他言語の類似機能

「デストラクタによるRAII」に近い機能を実現する手段は、JavaではAutoCloseableインターフェイスの実装とtry-with-resources文、C#ではSystem.IDisposableインターフェイスの実装とusing文である。なお、C++/CLIでは、マネージ型にデストラクタを定義するだけでIDisposableインターフェイスを暗黙的に実装したことになる。

Objective-Cでは、インスタンスの参照カウントがゼロになったときにdeallocメソッドがランタイムによって自動的に呼ばれる。このメソッド内に各種の後始末処理(Objective-Cの管理下にないリソースの解放など)を記述することができる。Swiftでの該当機能はデイニシャライザdeinitである。

脚注

関連項目

Tags:

デストラクタ ファイナライザデストラクタ 他言語の類似機能デストラクタ 脚注デストラクタ 関連項目デストラクタC++DelphiRust (プログラミング言語)オブジェクト指向サブルーチンプログラミング言語メソッド (計算機科学)英語

🔥 Trending searches on Wiki 日本語:

本田望結ONE PIECEの登場人物一覧子安武人響け! ユーフォニアム文禄・慶長の役石川恋徳川家治機動戦士ガンダムSEEDマイケル・ジャクソン岸田文雄アシタノカレッジ磯村勇斗アルコ&ピース鬼滅の刃酒々井ちびっこ天国中条あやみ徳川治済馬渕磨理子ドナルド・キーンウィリアム・アダムス金玉均笘篠賢治佐々木俊輔ちいかわ なんか小さくてかわいいやつDJ松永カネミ油症事件カピバラMリーグトム・コンティ山下智茂森香澄フォーミュラEラーズ・ヌートバーアローン・イン・ザ・ダーク仲里依紗それって!?実際どうなの課家なき子 (1994年のテレビドラマ)聖金曜日松田聖子ナ・イヌ名探偵コナンの登場人物清水麻椰デーブ・ロバーツ (外野手)山下智久ハリー・ポッターシリーズプロジェクトX〜挑戦者たち〜市川実日子高峰秀子三遊亭円楽 (6代目)シーザリオ前田健太天彩峰里河北彩伽田沼意知(G)I-DLEムーキー・ベッツイギリスキスカ島撤退作戦ちゅらさん帝銀事件東山紀之地下鉄サリン事件ハズビン・ホテルREINA (タレント)西丸優子アルベルト・アインシュタイン市川実和子尼神インター手塚理美シトリニン俺だけレベルアップな件石井優中村愛美宙組 (宝塚歌劇)三島由紀夫とんねるずハラミちゃん🡆 More