Main Content

コード生成におけるハンドル オブジェクトの制限事項

コード ジェネレーターはハンドル オブジェクトの存続期間を静的に判別します。ハンドル オブジェクトを使用する場合、この静的解析に特定の制約があります。

静的解析を利用すると、生成されたコードは参照カウントやガベージ コレクションなどの動的メモリ管理スキームに依存するのではなく、メモリを再利用できます。コード ジェネレーターは、動的メモリ割り当てと実行時の自動メモリ管理を回避できます。これらの生成されたコードの特性は、セーフティ クリティカルなリアルタイム アプリケーションで重要です。

制限事項については、以下を参照してください。

コード ジェネレーターは、すべての変数が使用前に定義されているか解析します。未定義の変数またはデータ型があると、コード生成中にエラーが発生します。状況によっては、コード ジェネレーターは、ハンドル オブジェクトへの参照が定義されているかどうか判別できないことがあります。ハンドル オブジェクトへの参照が未定義で表示されるを参照してください。

ループ外の変数はループ内に割り当てられたハンドル オブジェクトを参照できない

ハンドル クラス 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 = xif 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 = myclsif 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 つの変数がメモリ内の同じ場所を参照しています (xy および v.prop)。コード ジェネレーターは、x.propy.prop が同じ値を共有していると判別します。コード ジェネレーターは、ハンドル オブジェクトのプロパティ v.prop.prop がその定義を x.prop および y.prop と共有していることを判別できません。このエラーを回避するには、v.prop.prop を直接定義します。