3

背景情報については、この質問を参照してください。

TDigits = AnsiString;  //Should be `= array of NativeUInt`, but string has COW

TBigint = record
  Digit: TDigits; // Unsigned number, LSB stored in D[0], MSB in D[size-1]
  Size: Byte; // Mininum = 4, maximum 127.
  MSI: Byte; // Most significant (native)integer minimum=1, maximum=127
  Sign: Shortint;
  class operator Implicit(a: Integer): TBigint;

背景
私は (ほぼ) 通常の整数のように動作する bignum クラスを使用しています。
したがってa:= 1000000*10000000*12000000*10000000*1000000;、完全に有用な結果が得られます。この目的のために、 のレコードを使用しclass operatorsます。これらは、自動型変換と初期化をトリガーします。aを別の に割り当てているため、変換がない場合を
除きます。 TBigintTBigint

ソリューション
Ansistring を使用してコア データを保存します。コピー オン ライトがあり、必要に応じて自身のクローンを作成します。

問題: (文字列を変更していることを Delphi が認識しない場合、COW は機能しません)として偽装され
た Digit を操作する純粋なアセンブラ ルーチンがいくつかあります。 dynamic arrayAnsistring

ただし、次のようなことをすると:

Label1.Caption:= BigintToStr(b);
..... this fires:

function BigintToStr(const X: TBigint): AnsiString;
var
  ..
  LocX:= x;   <<-- assignment, locX and X are joined at the hip.
  repeat
    D := DivBigint(LocX, 1000000000, LocX); <<-- this routine changes LocX
                                 ^^+-- but assembler routines bypass COW

X股関節が関節でLocX、一方に何が起こっても他方に起こります。明らかに、Delphi は asm ルーチンが変更
されていることを認識していないため、COW が適切です。DivBigintLocX


ルーチンを次のように変更した場合の回避策:

function BigintToStr(const X: TBigint): AnsiString;
var
  ..
  LocX:= x;
  LocX.Digit[2]:= #0;  <<-- inconsequential change to force COW.
  repeat
    D := DivBigint(LocX, 1000000000, LocX);

Delphi はすべて手がかりをつかみ、問題なく動作します。 LocXリンクが解除され、Xすべて正常に動作します。
ただし、空きスペースの途中でばかげた変更を加えたくありません。

文字列でトリガーCOWを強制する適切な/適切な/公式*の方法はありますか?
システムコールのようなものでしょうか。

※お好きな選択肢に〇をつけてください(手描きの〇付き)

4

2 に答える 2

6

コメントにする必要がありますが、もっとスペースが必要です...

UniqueString電話または同等の必要がある場合。
動的レコードを保持することもできます。

マニュアルからの引用:

SetLength の呼び出しに続いて、S は一意の文字列または配列を参照することが保証されます。つまり、参照カウントが 1 の文字列または配列です。変数を再割り当てするのに十分なメモリがない場合、SetLength は EOutOfMemory 例外を発生させます。

この動作は、 を呼び出す場合にも適用されることに注意してくださいSetLength(Length(myArray));
Delphi がコピーを作成し、問題を解決します。

varしたがって、AnsiStrings を複雑にする必要はありません。結局のところ、レコードをパラメーターとして受け入れるすべてのメソッドで SetLength を呼び出す限りは。

利点これには、 (よくあることですが) 配列を展開するために
呼び出すと、追加されたスペースがゼロで初期化されるという追加の利点があります。SetLengthAnsiString では何も起こりません。

array of TXYZさらに、要素のサイズは既にわかっているため、サイズの変換に煩わされる必要はありません。AnsiString を使用する場合は、あちこちに追加する必要があります* SizeOf(somestruct)

型キャストが不要なため、コードが簡素化されます。デバッガーでは、データが設計どおりに表示されます。

SetLength を呼び出すだけで、動的配列が COW になります。

ご覧のとおり、2 つのインスタンスはリンクされていません。

于 2013-09-21T16:03:15.730 に答える