1

動的配列を宣言するときは、たとえば次のようにします

var
  MyArray: array of Byte;

このようにして、コンパイラは、スコープ外になったときにその変数 (配列) をファイナライズする必要があることを認識します。しかし、動的配列をこのようにポインターとして宣言したい

var
  MyArray: Pointer;

実行時にオンザフライでそのような配列を初期化(長さを設定)する方法を知っています。問題は、コンパイラがファイナライズする必要があるという手がかりがないことです。スコープ外のときにそのポインターを配列としてファイナライズするようにコンパイラーに指示する方法があるかどうかを知りたいです。初めてアレイを初期化するとき、私は彼にそれを伝えます。

私はこれがハックであることを知っています。それが正しい方法ではないと聞きたくありません。私には非常に具体的な願い (問題) があり、それが実現可能かどうか知りたいです。コンパイラがコンパイラの魔法でそれを行うのとは違うと思います。

編集

質問を簡単にしたかったのですが、もっと知りたいという人もいるので、もっとお話しします。質問とは関係ないと思いますが、とりあえず。

各レコードで 4 バイト (または 64 ビット システムでは 8 バイト) を節約したいと考えています。それは遊びのようなものです。私のアイデアは、変数レコード TSimpleData 内に動的配列へのポインターを挿入することでした。この種のレコードは、ファイナライズが必要な変数を受け入れません。理由は完全に明確です。しかし、後でファイナライズに登録する方法があるかどうか知りたかったのです。私は 99% 方法がないことを確信していましたが、100% 確実であることを求めても害はありません。以下は、問題の関連コードです。FComplexData を単純なポインターとして TSimpleData の一部にしたいと考えています。

 TSimpleData = record { do not pack this record; it is compiler-generated }
    case Byte of
      atInteger:   (VInteger: Integer);
      atCardinal:  (VCardinal: Cardinal);
      atBoolean:   (VBoolean: Boolean);
      atObject:    (VObject: TObject);
      atPointer:   (VPointer: Pointer);
      atClass:     (VClass: TClass);
      atWideChar:  (VWideChar: WideChar);
      atChar:      (VChar: AnsiChar);
    {$IFDEF AnyValue_UseLargeNumbers}
      atInt64:     (VInt64: Int64);
      atExtended:  (VExtended: Extended);
    {$ENDIF}   
  end;

  TAnyValue = packed record   private
    FValueType: TValueType;   
  {$IFNDEF AnyValue_NoInterfaces}
    FInterface: IInterface;   
  {$ENDIF}
    FSimpleData: TSimpleData;
    FComplexData: array of Byte;
    ...    
  end;
4

2 に答える 2

2

あなたが求めることをする方法はありません。動的配列をコンパイラーに自動的にファイナライズさせる唯一の方法は、動的配列を宣言することです。実際に宣言せずに動的配列変数をコードに「挿入」することはできません。

宣言されたら、そのポインターをそれに割り当てることができ、他の動的配列と同じようにクリーンアップされます。必要に応じて、その動作を関数にラップできます。

procedure CleanUpArray(P: Pointer);
var
  Arr: array of Byte;
begin
  Pointer(Arr) := P;
end;

を呼び出すと、変数にCleanUpArray(MyArray)格納されている動的配列Pointerがクリーンアップされます — 参照カウントが 1 減り、メモリが解放される可能性があります — ただし、 に格納されている値は変更されMyArrayません。

この関数が機能するのは、型キャストが動的配列代入ステートメントに固有の参照カウント コードを無効にするためです。つまり、基本的にビットごとのコピーを行います。ただし、関数が戻ると、コンパイラが挿入した変数のクリーンアップ コードが実行されます。変数が null ではないことに気付くため、その変数に動的配列参照があると想定し、配列がクリーンアップされます。

変数を実際の型で宣言する方がはるかに優れています。これにより、ユーザーとコンパイラーの作業が楽になります。

于 2013-02-07T19:49:23.270 に答える
0

私自身の質問に答えるために、これを行う簡単な方法はありません。しかし、私は簡単にあきらめないので、解決策が作成されました:

http://www.cromis.net/blog/2013/02/tanyvalue-an-attempt-to-make-the-best-variable-data-container/

基本的に、Embarcadero や Borland が何年も前にすべきだったことを実行します。

于 2013-02-14T13:54:58.610 に答える