Main Content

ハンドル クラスのデストラクター

基礎知識

"クラス デストラクター" – ハンドル クラスのオブジェクトを破棄する前に MATLAB® が暗黙的に呼び出す delete と名付けられたメソッドです。ユーザー定義のコードで delete を明示的に呼び出して、オブジェクトを破棄することもできます。

"無効なデストラクター" – 有効なデストラクターの構文要件を満たさない delete と名付けられたメソッドです。そのため、MATLAB はハンドル オブジェクトを破棄するときに、このメソッドを暗黙的に呼び出しません。値クラスの delete という名前のメソッドはデストラクターではありません。HandleCompatible 属性を true に設定する値クラスの delete という名前のメソッドは、デストラクターではありません。

オブジェクトのライフサイクル

メソッドの属性

ハンドル クラスのデストラクター メソッドの構文

MATLAB は、クラスのオブジェクトを破棄するときにハンドル クラスのデストラクターを呼び出します。delete が適切な構文で通常のメソッドとして定義されている場合にのみ、MATLAB は delete と名付けられたメソッドをクラス デストラクターとして認識します。

delete メソッドが有効なクラス デストラクターであるための条件は、次のとおりです。

  • クラス オブジェクトであるスカラー入力引数を 1 つ定義していなければならない

  • 出力引数を定義しない

  • SealedStatic または Abstract ではない

  • 入力引数の検証に arguments ブロックを使用できない

さらに、delete メソッドは次のことを "行いません"

  • オブジェクトが無効な場合でも、エラーをスローする

  • 破棄されているオブジェクトに新しいハンドルを作成する

  • サブクラスのメソッドを呼び出すまたはプロパティにアクセスする

クラスのオブジェクトを破棄する場合、MATLAB は非準拠の delete メソッドは呼び出しません。非準拠の delete メソッドがあると、handle クラスの delete メソッドの優先順位が低くなり、オブジェクトの破棄が妨げられる場合があります。

ハンドル互換の値クラスで定義された delete メソッドは、ハンドル サブクラスによって delete メソッドが継承された場合でも、デストラクターではありません。ハンドル互換クラスの詳細については、ハンドル互換クラスを参照してください。

delete を通常のメソッドとして宣言するには、次のようにします。

methods
   function delete(obj)
      % obj is always scalar
   ...
   end
end

配列の要素単位で呼び出される delete

MATLAB は、delete メソッドを配列内の要素ごとに別々に呼び出します。このため、delete メソッドには、呼び出しごとに 1 つのスカラー引数のみが渡されます。

削除されたハンドルに delete を呼び出してもエラーにはならず、何も処理は行われません。この設計により delete は、有効なオブジェクトと無効なオブジェクトが混在したオブジェクト配列を操作できるようになります。

delete メッソドを実行している間のハンドル オブジェクト

オブジェクトに対して delete メソッドを呼び出すと、必ずそのオブジェクトが破棄されます。MATLAB コードで delete の呼び出しが明示的に行われるか、または MATLAB によって呼び出されると、オブジェクトがどのワークスペースからもアクセスできなくなるため、そのオブジェクトが破棄されます。一度 delete メソッドを呼び出すと、オブジェクトの破棄を中止したり止めたりすることはできません。

delete メソッドは、削除中のオブジェクトのプロパティにアクセスできます。MATLAB では、delete メソッドによってオブジェクトのクラスやすべてのスーパークラスへの実行が完了するまで、それらのプロパティは破棄されません。

delete メソッドが、削除されるオブジェクトへのハンドルを含む新しい変数を作成した場合、それらのハンドルは無効です。delete メソッドが実行を終了すると、いずれのワークスペースのいずれの変数でも削除されたオブジェクトへのハンドルが無効になります。

メソッドの呼び出し時にオブジェクトの破棄が開始されるため、isvalid メソッドは delete メソッド内のハンドル オブジェクトに対して false を返します。

MATLAB は、作成順序と逆に delete メソッドを呼び出します。つまり、MATLAB は、スーパークラスの delete メソッドの前にサブクラスの delete メソッドを呼び出します。

スーパークラスで、プロパティがサブクラスによって管理されることが仮定されている場合、スーパークラスからその delete メソッドでプロパティにアクセスすべきではありません。たとえば、サブクラスが、継承した抽象プロパティを使用してオブジェクト ハンドルを格納する場合、サブクラスでは delete メソッド内でこのオブジェクトを破棄する必要がありますが、スーパークラスでは delete メソッド内でそのプロパティにアクセスすべきではありません。

部分的に作成されたオブジェクトの破棄のサポート

オブジェクトの作成中に発生するエラーが原因で、オブジェクトが完全に作成される前に delete が呼び出されることがあります。そのため、クラスの delete メソッドは部分的に作成されたオブジェクトを扱えなければなりません。

たとえば、PartialObject クラスの delete メソッドは、Data プロパティに含まれているデータにアクセスする前にこのプロパティが空であるかどうかを判別します。コンストラクター引数を Name プロパティに割り当てる際にエラーが発生した場合、MATLAB は部分的に作成されたオブジェクトを delete に渡します。

classdef PartialObject < handle
   properties
      % Restrict the Name property
      % to a cell array
      Name cell
      Data
   end
   methods
      function h = PartialObject(name)
         if nargin > 0
            h.Name = name;
            h.Data.a = rand(10,1);
         end
      end
      function delete(h)
         % Protect against accessing properties
         % of partially constructed objects
         if ~isempty(h.Data)
            t = h.Data.a;
            disp(t)
         else
            disp('Data is empty')
         end
      end
   end
end

必要な cell 配列の代わりに char ベクトルを指定してコンストラクターを呼び出すと、エラーが発生します。

obj = PartialObject('Test')

MATLAB は部分的に作成されたオブジェクトを delete メソッドに渡します。Name プロパティの設定中にエラーが発生したため、コンストラクターは Data プロパティの値を設定していません。

Data is empty
Error setting 'Name' property of 'PartialObject' class:
...

デストラクター メソッドを定義するタイミング

delete メソッドを使用して、MATLAB がオブジェクトを破棄する前にクリーンアップ操作を実行します。MATLAB は、Ctrl+C やエラーにより実行が中断される場合でも、確実に delete メソッドを呼び出します。

ハンドル クラス作成中にエラーが発生すると、MATLAB は、プロパティと初期化された基底クラスに含まれる任意のオブジェクトのデストラクターと共に、クラス デストラクターをオブジェクトに呼び出します。

たとえば、メソッドで書き込み用のファイルを開き、そのファイルを delete メソッドで閉じるとします。delete メソッドでは、オブジェクトがその FileID プロパティに格納するファイル識別子で fclose を呼び出すことができます。

function delete(obj)
   fclose(obj.FileID);
end 

クラス階層内のデストラクター

クラスの階層を作成すると、各クラスで独自の delete メソッドを定義できます。MATLAB は、オブジェクトを破棄するときに階層内の各クラスの delete を呼び出します。handle サブクラスで delete メソッドを定義しても、handle クラスの delete メソッドはオーバーライドされません。サブクラスの delete メソッドはスーパークラスの delete メソッドを拡張します。

シールされた Delete メソッドの継承

デストラクターを Sealed にすると、有効なデストラクターを定義できません。Sealed delete メソッドを定義するクラスをインスタンス化しようとすると、MATLAB からエラーが返されます。

通常、Sealed としてメソッドを宣言すると、サブクラスでそのメソッドをオーバーライドできなくなります。ただし、有効なデストラクターではない delete という名前の Sealed メソッドは、サブクラスが独自のデストラクターを定義することを防ぎません。

たとえば、有効なデストラクターではないが Sealed である delete という名前のメソッドをスーパークラスで定義した場合、サブクラスは次のようになります。

  • 有効なデストラクターを定義できる (名前は必ず delete とする)。

  • delete という名前のメソッドを無効なデストラクターとして定義できない。

異種混合階層にあるデストラクター

異種混合クラス階層では、異種混合配列が渡されるすべてのメソッドはシールされていなければなりません。ただし、この規則はクラス デストラクター メソッドには適用されません。デストラクター メソッドはシールできないので、シールされてはいないがデストラクターとして機能する有効なデストラクターを、異種混合階層で定義できます。

異種混合階層については、異種混合クラス階層の設計を参照してください。

オブジェクトのライフサイクル

MATLAB は、オブジェクトのライフサイクルの終了時に、delete メソッドを呼び出します。オブジェクトのライフサイクルは、そのオブジェクトが以下の場合に終了します。

  • どこからも参照されていない

  • ハンドルに対して delete を呼び出すことによって明示的に削除される

関数の内部

ローカル変数または入力引数によって参照されるオブジェクトのライフサイクルは、その変数が代入されたときから、再び代入されたり、クリアされたり、あるいはその関数内または任意のハンドル配列内での参照が行われなくなるまで存続します。

変数は、明示的にクリアされるかその関数が終了すると、スコープの外に出ます。変数がスコープ外になり、その値が delete メソッドを定義するハンドル クラスに属する場合は、MATLAB によってそのメソッドが呼び出されます。MATLAB は、関数内の変数の順序を定義しません。複数の値が同じ関数にある場合、MATLAB がそれぞれの値を破棄する順序は予測できません。

ハンドル オブジェクトを破棄する一連の過程

MATLAB は、オブジェクトを破棄する場合、以下のシーケンスで delete メソッドを呼び出します。

  1. オブジェクトのクラスの delete メソッド

  2. 各スーパークラスの delete メソッドは、直上のスーパークラスから始め、最も一般のスーパークラスまで階層を上がります。

MATLAB は、クラス定義に指定した順序で、同じ階層レベルでスーパークラスの delete メソッドを呼び出します。たとえば、以下のクラス定義では supclass1supclass2 の前に指定されています。MATLAB は、supclass1delete メソッドを supclass2delete メソッドの前に呼び出します。

classdef myClass < supclass1 & supclass2

delete メソッドの呼出し後に、MATLAB は、メソッドが呼び出されたクラスに属するプロパティ値を破棄します。ただし、クラスのスコープ外でまだ参照されているハンドル オブジェクトがプロパティ値に含まれている場合、含まれているオブジェクトに対して delete を呼び出しても、プロパティのハンドル オブジェクト自体は削除されません。他の既存の参照からは引き続きアクセスできます。

スーパークラスの delete メソッドは、サブクラスに属する、メソッドの呼び出しやプロパティへのアクセスができません。

循環参照のあるオブジェクトの破棄

ある一連のオブジェクトが、巡回的なグラフを形成する一連のオブジェクトを参照しているとします。この場合、MATLAB は以下の動作をします。

  • 循環内でのみ参照されているオブジェクトを破棄する

  • 循環外の MATLAB 変数から任意のオブジェクトに対して外部参照がある場合は、オブジェクトを破棄しない

MATLAB は、作成順序とは逆の順番でオブジェクトを破棄します。詳細については、delete メッソドを実行している間のハンドル オブジェクトを参照してください。

オブジェクトの delete メソッドへのアクセスの制限

オブジェクトで次のように delete を明示的に呼び出して、ハンドル オブジェクトを破棄します。

delete(obj)

クラスは、delete メソッドの Access 属性を private に設定して、オブジェクトの明示的な破棄を回避できます。ただし、クラスのメソッドは private delete メソッドを呼び出すことができます。

クラスの delete メソッド Access 属性が protected である場合、そのクラスおよびサブクラスのメソッドのみがそのクラスのオブジェクトを明示的に削除できます。

ただし、オブジェクトのライフサイクルが終了すると、MATLAB はメソッドの Access 属性とはかかわりなく、オブジェクトの破棄に際してオブジェクトの delete メソッドを呼び出します。

継承されたプライベートな Delete メソッド

クラス デストラクターの動作は、オーバーライドされたメソッドの通常の動作とは異なります。MATLAB は、delete メソッドが public でない場合も含め、破棄するときに各スーパークラスのそれぞれの delete メソッドを実行します。

オブジェクトの delete メソッドを明示的に呼び出すと、MATLAB はオブジェクトを定義しているクラスで delete メソッドの Access 属性をチェックしますが、オブジェクトのスーパークラス内ではチェックしません。privatedelete メソッドのあるスーパークラスは、サブクラスのオブジェクトの破棄を回避できません。

シールされたクラスには、プライベートな delete メソッドを宣言することが最も論理的です。クラスがシールされていない場合、サブクラスはパブリックのアクセスを指定して独自の delete メソッドを定義できます。パブリック サブクラス delete メソッドが明示的に呼び出される結果として、MATLAB がスーパークラスの delete プライベート メソッドを呼び出すためです。

無効なデストラクター Delete メソッド

クラスは有効なクラス デストラクターではない delete という名前のメソッドを実装できます。MATLAB は、オブジェクトを破棄するときにこのメソッドを暗黙的に呼び出しません。この場合、delete は通常のメソッドのように動作します。

たとえば、スーパークラスが無効なデストラクターである delete と名付けられた Sealed メソッドを実装する場合、MATLAB はサブクラスがこのメソッドをオーバーライドすることを許可しません。

値クラスで定義された delete メソッドは、クラス デストラクターになることはできません。

MATLAB オブジェクトへの外部参照

MATLAB は、オブジェクトのライフサイクルのうち、外部言語によって独自にオブジェクトのライフサイクル管理 (つまり、ガーベジ コレクション) が実行されるものを管理しません。外部環境は MATLAB にいつ外部参照が破棄されたかを通知しないため、MATLAB は循環参照で使用されるオブジェクトをいつ安全に破棄できるかを検出できません。

MATLAB オブジェクトへの外部参照を回避できない場合は、MATLAB でオブジェクトを破棄することにより循環参照を明示的に解消します。

次の節では、MATLAB オブジェクトを参照する Java® オブジェクトを使用するときにこの状況を管理する方法を説明します。

デストラクターの実行を回避できる Java 参照

Java は、MATLAB オブジェクトが使用するオブジェクトのデストラクターをサポートしません。このため、Java オブジェクトと MATLAB オブジェクトの両方を含むアプリケーションで使用されるすべてのオブジェクトのライフサイクルを管理することが重要です。

MATLAB オブジェクトへの参照を保持する Java オブジェクトは MATLAB オブジェクトの削除を回避できます。この場合、MATLAB は、そのオブジェクトを参照するハンドル変数がない場合でも、ハンドル オブジェクトの delete メソッドを呼び出しません。delete メソッドを確実に実行するには、ハンドル変数がスコープ外になる前に、オブジェクトで明示的に delete を呼び出します。

MATLAB オブジクトを参照する Java オブジェクトのコールバックを定義するときに問題が起きる可能性があります。

たとえば、CallbackWithJava クラスが Java com.mathworks.jmi.Callback オブジェクトを作成し、クラス メソッドをコールバック関数として割り当てます。その結果、関数ハンドル コールバック経由でのハンドル オブジェクトへの参照をもつ Java オブジェクトが生成されます。

classdef CallbackWithJava < handle
   methods
      function obj = CallbackWithJava
         jo = com.mathworks.jmi.Callback;
         set(jo,'DelayedCallback',@obj.cbFunc); % Assign method as callback
         jo.postCallback
      end
      function cbFunc(obj,varargin)
         c = class(obj);
         disp(['Java object callback on class ',c])
      end
      function delete(obj)
         c = class(obj);
         disp(['ML object destructor called for class ',c])
      end
   end
end

関数内で CallbackWithJava オブジェクトを作成するとします。

function testDestructor
   cwj = CallbackWithJava
   ...
end

CallbackWithJava クラスのインスタンスを作成すると、com.mathworks.jmi.Callback オブジェクトが作成され、コールバック関数が実行されます。

testDestructor
cwj = 

  CallbackWithJava with no properties.

Java object callback on class CallbackWithJava

ハンドル変数 cwj は、関数ワークスペース内にのみ存在します。ただし、MATLAB は、この関数の終了時にクラス delete メソッドを呼び出しません。com.mathworks.jmi.Callback オブジェクトはそのまま存在し、CallbackWithJava クラスのオブジェクトへの参照を保持します。これにより、MATLAB オブジェクトの破棄が回避されます。

clear classes
Warning: Objects of 'CallbackWithJava' class exist.  Cannot clear this class or
any of its superclasses. 

アクセスできないオブジェクトの発生を避けるために、MATLAB オブジェクトのハンドルを失う前に delete を明示的に呼び出します。

function testDestructor
   cwj = CallbackWithJava
   ...
   delete(cwj)
end

アプリケーションでのオブジェクトのライフサイクルの管理

Java またはその他の外部言語のオブジェクトを使用する MATLAB アプリケーションは、関連するオブジェクトのライフサイクルを管理する必要があります。一般的なユーザー インターフェイス アプリケーションは MATLAB オブジェクトから Java オブジェクトを参照し、MATLAB オブジェクトを参照する Java オブジェクトでコールバックを作成します。

これらの循環参照は、以下に示すさまざまな方法で解消できます。

  • 不要になった MATLAB オブジェクトに対して delete を明示的に呼び出す

  • MATLAB オブジェクトを参照する Java オブジェクトのコールバックの登録を解除する

  • Java コールバックと MATLAB オブジェクトの両方を参照する中間ハンドル オブジェクトを使用する

関連するトピック