5

文字列へのポインタがどのように機能するかを理解しようとしています。私は誰かによって書かれたコード (正確にはオリジナルではない) を持っています。

var
  STR: string;
  pStr: ^string;
begin
  STR := 'Hello world';
  New(pStr);
  pStr^ := STR;

  PostMessage(Handle, WM_USER+1, wParam(pStr), 0);
end;

メッセージハンドラーがメッセージを取得し、ポインターに文字列が含まれていることは確かです。これは操作できますが、これらの操作の「内部」では何が起こりますか?

小さなプロジェクトを作ってみました。文字列を str ポインタが指すものに割り当てると、実際には元の文字列のrefcountが増加し、文字列のコピーは作成されないと思いましたが、refcountは1のままで、内容をコピーしたようです。

それで、何が起こったのですか?ポインターを呼び出すNewと、空の文字列が割り当てられますよね? 割り当て後、ポインターが指す文字列の refcount/length をこのように調べようとしましたPChar(@pStr^[1])[-8]が、ナンセンス (14) が返され、長さバイトも間違っていました。

さらに、質問は、Windowsメッセージングを介して文字列を渡すような方法でポインターを使用しても安全ですか?

4

1 に答える 1

8

New(pStr)stringヒープにa を割り当て、それへのポインターを返します。はマネージド型であるためstring、文字列はデフォルトで初期化され、空の文字列になります。astringはポインターとして実装されているため、基本的にはポインターへのポインターです。

メッセージを自分のプロセスにのみ投稿する限り、コードはまったく問題ありません。メッセージのペイロードはポインターであるため、プロセスの仮想アドレス空間のコンテキストで何かを意味するだけです。別のプロセスに送信したい場合は、IPC メカニズムが必要です。

メッセージをキューから取り出すコードでは、文字列を破棄する必要があることは明らかです。このようなもの:

var
  p: ^string;
  str: string;
....
p := Pointer(wParam);
str := p^; 
Dispose(p);

参照カウントと長さを照会するコードが間違っています。正しく行う方法は次のとおりです。

{$APPTYPE CONSOLE}

var
  pStr: ^string;
  p: PInteger;

begin
  New(pStr);
  pStr^ := 'Hello world';

  p := PInteger(pStr^);
  dec(p);
  Writeln(p^); // length
  dec(p);
  Writeln(p^); // ref count

  Readln;
end.

出力:

11
1
于 2013-10-22T08:16:16.090 に答える