Delphi AnsiString Manipulation - PAnsiChar становится поврежденным?

Я использую следующий подход для перемещения и манипулирования AnsiString, Это работает большую часть времени, но иногда указатель на строку перестает функционировать. Учитывая следующий код:

var
  s: AnsiString;
  p: PAnsiChar;
  offset, idx, cnt: Integer;
begin
  s := 'some>very>long>string>with>field>delimiters>';
  p := @s[1];
  offset := 1;

  // find the 5th field
  cnt := 5;
  repeat
    idx := AnsiString.AnsiPos('>', p);
    Inc(p, idx);
    Inc(offset, idx);
    Dec(cnt);
  until cnt = 0;

  // insert a new field after the 5th field
  Insert(AnsiString('something new>'), s, offset);

  // skip other fields
  // insert other values
  // repeat
end;

При отладке сразу после repeat..until цикл заканчивается, вы можете посмотреть на инспектора и увидеть, что p = 'field>delimiters>', После Insert() заявление, s = 'some>very>long>string>with>something new>field>delimiters>' а также p = 'something new>field>delimiters>' в инспекторе. Это как и ожидалось.

Моя настоящая строка длиной в несколько тысяч символов. Этот метод перемещения по строке и добавления новых полей работает десятки раз, а затем внезапно перестает работать. p больше не показывает вставленное значение в начале строки после вызова Insert(), p кажется, не знает, что s изменился...

Почему p правильно ссылаться на символ на s после большинства Insert() заявление, и вдруг перестают работать после некоторых звонков Insert()?

(Я нашел ответ на свой вопрос во время набора текста. Ответ кажется очевидным сейчас, но не так, пока я боролся с проблемой. Возможно, размещение вопроса и ответа поможет кому-то еще...)

1 ответ

Решение

Когда вы звоните Insert()менеджер памяти переместит AnsiString в новое место в памяти, если не хватает дополнительной непрерывной памяти для расширения буфера в его текущем месте памяти. Это оставляет p указание на старую область памяти, которая не содержит измененную строку и, вероятно, приведет к нарушениям доступа.

Добавление одной строки кода для повторной инициализации p после каждого Insert() Заявление устраняет проблему.

var
  s: AnsiString;
  p: PAnsiChar;
  offset, idx, cnt: Integer;
begin
  s := 'some>very>long>string>with>field>delimiters>';
  p := @s[1];
  offset := 1;

  // find the 5th field
  cnt := 5;
  repeat
    idx := AnsiString.AnsiPos('>', p);
    Inc(p, idx);
    Inc(offset, idx);
    Dec(cnt);
  until cnt = 0;

  // insert a new field after the 5th field
  Insert(AnsiString('something new>'), s, offset);
  p := @s[offset];                                 // <- this fixes the issue

  // skip other fields
  // insert other values
  // repeat
end;
Другие вопросы по тегам