Тонкости работы со строками в Delphi - Побочное изменение

ОГЛАВЛЕНИЕ


Побочное изменение

Из-за того, что две одинаковые строки AnsiString разделяют одну область памяти, на неожиданные эффекты можно натолкнуться, если модифицировать содержимое строки в обход стандартных механизмов. Следующий код (пример SideChange) иллюстрирует такую ситуацию:
procedure TForm1.Button1Click(Sender: TObject);
var
  S1, S2: string;
  P: PChar;
begin
  S1 := 'Test';
  UniqueString(S1);
  S2 := S1;
  P := PChar(S1);
  P[0] := 'F';
  Label1.Caption := S2;
end;
В этом примере требует комментариев процедура UniqueString. Она обеспечивает то, что счётчик ссылок на строку будет равен единице, т.е. для этой строки делается уникальная копия. Здесь это понадобилось для того, чтобы строка S1 хранилась в динамической памяти, а не в сегменте кода, иначе мы получили бы Access violation, как и во втором случае рассмотренного ранее примера Constants.

В результате работы этого примера на экран будет выедено не "Test", а "Fest", хотя значение S2, казалось бы, не должно меняться, потому что мы изменения, которые мы делаем, касаются только S1. Но более внимательный анализ подсказывает объяснение: после присваивания S2 := S1 счётчик ссылок строки становится равным двум, а сама строка разделяется двумя указателями: S1 и S2. Если бы мы попытались изменить непосредственно S1, сначала была бы создана копия этой строки, а потом были бы сделаны изменения в этой копии, а оригинал, на который указывала бы S2, остался бы без изменений. Но, использовав PChar, мы обошли механизм копирования, поэтому строка осталась в единственном экземпляре, и изменения затронули не только S1, но и S2.

В данном примере всё достаточно очевидно, но в более сложных случаях разработчик программы может и не подозревать, что строка, с которой он работает, разделяется несколькими переменными. Справка Delphi советует сначала обеспечить уникальность копии строки с помощью UniqueString и только потом работать с ней через PChar, если в этом есть необходимость.