3

動的配列を含むレコードがあります。ある配列変数を別の配列変数に割り当てる場合、実際にはその配列へのポインターのみが割り当てられるのが普通です。つまり、これを行うと、一方のサイズを変更するまで、両方の変数が同じ配列を指します。したがって、配列の別のコピーを変数に割り当てたい場合は、Copy()関数を使用します。

ただし、この場合、私の配列はレコードのフィールドです。

  TMyRec = record
    Value: integer;
    &Array: array of integer;
  end;

タイプTMyRecの2つの変数を宣言してから、一方を他方に割り当てると、両方のレコードの「配列」フィールドがメモリ内の同じアドレスを指します。

この種の問題を解決するために、次のように割り当て演算子をオーバーロードすることにしました。

TMyRec = record
  Value: integer;
  &Array: array of integer;
public
  class operator Implicit(Value: TMyRec): TMyRec;
end;

class operator TMyRec.Implicit(Value: TMyRec): TMyRec;
begin
  Result := Value;
  Result.&Array := Copy(Value.&Array);
end;

これが機能する場合、TMyRecord変数を相互に割り当てた後、レコード内のすべての配列フィールドを個別にコピーする必要はありません。

これが私がすることです:

var
  Rec1, Rec2: TMyRec;
begin
  Rec1.Value := 10;
  SetLength(Rec1.Array, 1);

  //I expected the "Implicit" method to be invoked here (but it is not...)
  Rec2 := Rec1;

  //if I do that, the Rec1.Array[0] will also be changed to 1 - I don't want that to happen
  Rec2.Array[0] := 1;
end;

演算子のオーバーロードを希望どおりに機能させる方法はありますか?問題は、デフォルトの代入演算子をオーバーロードしようとしていることです。それは不可能ですか?

4

3 に答える 3

7

インターフェイスを実装するオブジェクトインスタンス内に配列を配置し、そのインターフェイスへの参照をレコード内に格納できます。このように、インターフェイスを介して(したがって、オブジェクトを介して)配列に割り当てようとすると、参照カウントを確認し、コピーオンライトのセマンティクスを支援できます。

または、型に安全でないトリックを使用して配列の参照カウントを見つけ、複数の参照が存在する場合は書き込み前に手動でコピーすることもできます。ただし、これはサポートされておらず、動的配列の実装が変更された場合は機能しなくなります。

レコードにラップされたコピーオンライト配列構造を実装する方法を書きました。ジェネリック型として実装されていますが、代わりに具象配列型を使用することを妨げるものは何もありません。一般的な型ではありません。

于 2009-06-04T22:46:20.867 に答える
3

TMyRecのポインタを使用できます:

pMyRec = ^TMyRec;
TMyRec = record
  Value: integer;
  _Array: array of integer;
public
  class operator Implicit(Value: pMyRec): TMyRec;
end;

class operator TMyRec.Implicit(Value: pMyRec): TMyRec;
begin
  Result := Value^;
  Result._Array := Copy(Value^._Array);
end;

procedure TForm1.Button1Click(Sender: TObject);
var R1, R2 : TMyRec;
begin
  R1.Value := 1;
  SetLength( R1._Array, 2);
  R1._Array[0] := 1;
  R1._Array[1] := 2;

  R2 := @R1;
  R2._Array[0] := 3;
end;
于 2013-10-21T16:43:38.793 に答える
1

単純な割り当ては行わないでください。読みやすさを追求します。次のような独自の「RecCopy」プロシージャを作成します。

procedure RecCopy( const AFrom, ATo : TMyRec );
var
  I : integer;
begin
  ATo.Value := AFrom.Value;
  SetLength( ATo.Array, Length( AFrom.Array );
  For I := 0 to Length( AFrom.Array )-1 do
    ATo.Array[I] := AFrom.Array[I];
end;

配列コピーを実装するためのより良い方法を使用できることに注意してください:-)しかし、あなたは私の主張を理解しています。

于 2009-06-05T08:43:16.887 に答える