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;