6

次のコードは私のシステムで期待どおりに実行されますが、P変数が新しい値に変更された後に同じ値を持つことが保証されているかどうかはわかりません。MyArray[0]

procedure Test;
var
  MyArray: array of string;
  P : PChar;

begin
  SetLength(MyArray, 2);
  MyArray[0] := 'ABCD';
  MyArray[1] := '1234';

  // Is P guaranteed to have the same value all the time?
  P := PChar(MyArray[0]);

  MyArray[0] := MyArray[1];
  MyArray[1] := P;

  WriteLn(MyArray[0]);
  WriteLn(MyArray[1]);
end;
4

2 に答える 2

13

あなたのコードは技術的に無効です。依存すべきではない実装の詳細が原因で、まったく実行されるだけです。

コードの関連セクションを見てみましょう。

P := PChar(MyArray[0]);
MyArray[0] := MyArray[1];
MyArray[1] := P;   

まず、P が MyArray[0] の最初の文字を指すようにします。次に、MyArray[0] に代入します。この時点で、P が指している文字列バッファーを維持する理由はありません。それを参照する文字列変数はありません。参照カウントがゼロになったため、割り当てを解除する必要があります。これにより、その後の P の使用が無効になります。

その場合、なぜコードが実行されるのでしょうか? 使用する文字列はたまたまリテラルであるためです。したがって、それらは -1 に等しい参照カウントで格納され、文字列で使用される通常のヒープ割り当てルーチンをバイパスします。しかし、リテラルではない文字列値を使用すると、上記の段落で説明したことが実現します。そして、あなたの実際のコードはリテラルを使用していないと思います。

したがって、あなたの実際の質問はやや議論の余地があります。P ポインターは、メモリのブロックを指すだけです。ポインタを変更するまで、メモリの同じブロックを指し続けます。メモリのブロックの内容を変更した場合、それを逆参照すると、P はそれらの変更を認識します。これは、他のポインターと同様に単なるポインターです。

PChar 変数の使用には注意が必要です。あなたの使用では、これはコンパイラ管理オブジェクトへのアンマネージ ポインターです。これにより、エラーが発生する可能性が大きくなり、トラップに陥ってしまいます。文字列のコピーが必要な場合は、別の文字列変数にコピーします。

于 2012-12-29T08:09:52.657 に答える
2

文字列からPCharへの型キャストは、そのアドレスを取得することとは異なるようです。以下のコードを参照してください。文字列のアドレスを取得します。

procedure Test;
var
  MyArray: array of string;
  P : ^String;

begin
  SetLength(MyArray, 2);
  MyArray[0] := 'ABCD';
  MyArray[1] := '1234';

  // take the pointer
  P := @MyArray[0];

  WriteLn(MyArray[0]);
  WriteLn(MyArray[1]);
  WriteLn(P^);

  // when content of array changes, P^ will change as well
  MyArray[0] := 'HELLO';
  WriteLn(P^);
end;
于 2012-12-29T08:34:38.627 に答える