34.3.2 インデックス割り当ての最適化
Octaveの普遍的な遅延コピー値渡しセマンティクスは、ユーザ定義subsasgnメソッドのパフォーマンスに問題をもたらします。次の呼び出しを想像してください。subsasgn
ss = substruct ("()", {1});
x = subsasgn (x, ss, 1);
対応するメソッドは次のようになります。
function x = subsasgn (x, ss, val)
...
x.myfield (ss.subs{1}) = val;
endfunction
問題は、subsasgnメソッドのエントリ時に、x呼び出し元のスコープから がまだ参照されていることです。つまり、メソッドは割り当てを実行する前に、まず と を共有解除 (コピー) する必要がありますx。x.myfield呼び出しが完了すると、エラーが発生しない限り、結果はx呼び出し元のスコープ内ですぐに に割り当てられるため、 の以前の値はx.myfield忘れられます。したがって、Octave 言語は N 要素 (N は のサイズx.myfield) のコピーを意味しますが、実際には 1 つの要素を変更するだけで十分です。言い換えると、定数時間の操作が線形時間の操作に低下します。これは、本質的に大きな配列を格納するユーザー クラスにとって実際の問題になる可能性があります。
この問題を部分的に解決するために、Octave は m ファイルとしてコード化されたユーザー定義subsasgnメソッドに対して特別な最適化を使用します。組み込みの割り当て構文の結果としてメソッドが呼び出される場合 ( subsasgn上記のように直接呼び出しではない)、つまり でありx(1) = 1、 かつ、上記の例のようにメソッドが同一の入力引数と出力引数で宣言されている場合subsasgn、Octave は呼び出し元のスコープ内の のコピーを無視します x。したがって、メソッド実行中に に加えられた変更は、x 呼び出し元のコピーにも直接影響します。これにより、たとえば、単一の要素の変更に一定の時間がかかる多項式クラスを定義できます。
この最適化がもたらす影響を理解することが重要です。 の余分なコピーはx呼び出し元のスコープには存在しないため、 実行中にエラーが発生した場合に無効な状態のままにしないことは、呼び出し先のみのx責任となります。また、メソッドが部分的に変更されてエラーが発生した場合x、その変更は呼び出し元のスコープに影響します。x subsasgn 内の 削除または完全な置換はx何も行いませんが、インデックス付きの割り当てのみが問題となります。
この最適化によりコードの動作が変わる可能性があるため (特に書き方が悪ければ)、optimize_subsasgn_callsそれを制御する関数が用意されています。この機能はデフォルトで有効になっています。最適化を回避する別の方法は、次のように異なる出力引数と入力引数を持つ subsasgn メソッドを宣言することです。
function y = subsasgn (x, ss, val) ... endfunction