コード生成におけるハンドル オブジェクトの制限事項
コード ジェネレーターはハンドル オブジェクトの存続期間を静的に判別します。ハンドル オブジェクトを使用する場合、この静的解析に特定の制約があります。
静的解析を利用すると、生成されたコードは参照カウントやガベージ コレクションなどの動的メモリ管理スキームに依存するのではなく、メモリを再利用できます。コード ジェネレーターは、動的メモリ割り当てと実行時の自動メモリ管理を回避できます。これらの生成されたコードの特性は、セーフティ クリティカルなリアルタイム アプリケーションで重要です。
制限事項については、以下を参照してください。
コード ジェネレーターは、すべての変数が使用前に定義されているか解析します。未定義の変数またはデータ型があると、コード生成中にエラーが発生します。状況によっては、コード ジェネレーターは、ハンドル オブジェクトへの参照が定義されているかどうか判別できないことがあります。ハンドル オブジェクトへの参照が未定義で表示されるを参照してください。
ループ外の変数はループ内に割り当てられたハンドル オブジェクトを参照できない
ハンドル クラス mycls
と関数 usehandle1
について考えます。
classdef mycls < handle properties prop end methods function obj = mycls(x) obj.prop = x; end end end
function y = usehandle1(n) c = cell(1,n); for i = 1:n c{i} = mycls(i); % Handle object allocated inside loop end y = c{n}.prop; % Handle object referenced outside loop end
関数 usehandle1
のコードを生成しようとすると、コード ジェネレーターはエラーを生成します。エラーが発生する原因は次のとおりです。
ハンドル オブジェクトが
for
ループ内に割り当てられているこれらのハンドル オブジェクトのいずれかが
for
ループの外部で使用されている
永続変数が参照するハンドル オブジェクトはシングルトン オブジェクトでなければならない
永続変数がハンドル オブジェクトを参照する場合、コード ジェネレーターはプログラムの存続期間中にオブジェクトの 1 つのインスタンスしか許可しません。オブジェクトは "シングルトン" オブジェクトでなければなりません。シングルトン ハンドル オブジェクトを作成するには、永続変数の if isempty()
ガードにオブジェクトを作成するステートメントを囲みます。
たとえば、クラス mycls
と関数 usehandle2
について考えます。ステートメント inner = mycls
で作成される mycls
オブジェクトを p.prop
が参照するため、コード ジェネレーターは usehandle2
のエラーを報告します。このステートメントは usehandle2
を呼び出すたびに mycls
オブジェクトを作成します。
classdef mycls < handle properties prop end end
function usehandle2(x) assert(isa(x, 'double')); persistent p; inner = mycls; inner.prop = x; if isempty(p) p = mycls; p.prop = inner; end
ステートメント inner = mycls
および inner.prop = x
を if isempty()
ガード内に移動すると、コード生成は正常に実行されます。ステートメント inner = mycls
はプログラムの存続期間中に 1 回のみ実行されます。
function usehandle2(x) assert(isa(x, 'double')); persistent p; if isempty(p) inner = mycls; inner.prop = x; p = mycls; p.prop = inner; end
関数 usehandle3
について考えます。ステートメント myobj = mycls
で作成される mycls
オブジェクトを永続変数 p
が参照するため、コード ジェネレーターは usehandle3
のエラーを報告します。このステートメントは usehandle3
を呼び出すたびに mycls
オブジェクトを作成します。
function usehandle3(x) assert(isa(x, 'double')); myobj = mycls; myobj.prop = x; doinit(myobj); disp(myobj.prop); function doinit(obj) persistent p; if isempty(p) p = obj; end
myobj
を永続化し、ステートメント myobj = mycls
を if isempty()
ガード内に移動すると、コード生成は正常に実行されます。ステートメント myobj = mycls
はプログラムの存続期間中に 1 回のみ実行されます。
function usehandle3(x) assert(isa(x, 'double')); persistent myobj; if isempty(myobj) myobj = mycls; end doinit(myobj); function doinit(obj) persistent p; if isempty(p) p = obj; end
ハンドル オブジェクトへの参照が未定義で表示される
ハンドル オブジェクトのプロパティを別のオブジェクトにコピーする関数 refHandle
について考えます。この関数はシンプルなハンドル クラスと値クラスを使用します。MATLAB® では、関数はエラーなしで実行されます。
function [out1, out2, out3] = refHandle() x = myHandleClass; y = x; v = myValueClass(); v.prop = x; x.prop = 42; out1 = x.prop; out2 = y.prop; out3 = v.prop.prop; end
classdef myHandleClass < handle properties prop end end
classdef myValueClass properties prop end end
コード生成中に次のエラーが発生します。
'v.prop.prop' プロパティは、いくつかの実行パス上で定義されていません。
3 つの変数がメモリ内の同じ場所を参照しています (x
、y
および v.prop
)。コード ジェネレーターは、x.prop
と y.prop
が同じ値を共有していると判別します。コード ジェネレーターは、ハンドル オブジェクトのプロパティ v.prop.prop
がその定義を x.prop
および y.prop
と共有していることを判別できません。このエラーを回避するには、v.prop.prop
を直接定義します。