Чтение онлайн

на главную - закладки

Жанры

О чём не пишут в книгах по Delphi

Григорьев Антон Борисович

Шрифт:

Переменная типа

AnsiString
— это указатель на первый символ строки, как и в случае
PChar
. Разница в том, что перед этой строкой в память записывается дополнительная информация: длина строки и счетчик ссылок. Это позволяет компилятору генерировать код, автоматически выделяющий, перераспределявший и освобождающий память, выделяемую для строки. Работа с памятью происходит совершенно прозрачно для программиста, в большинстве случаев со строками
AnsiString
можно работать, вообще не задумываясь об их внутреннем устройстве. Символы в таких строках нумеруются с единицы, чтобы облегчить
перенос старых программ, использовавших строки типа
ShortString
.

Счетчик ссылок позволяет реализовать то, что называется copy-on-demand, копирование по необходимости. Если у нас есть две переменные

S1
,
S2
типа
AnsiString
, присваивание вида
S1 := S2
не приводит к копированию всей строки. Вместо этого в указатель
S1
копируется значение указателя
S2
, а счетчик ссылок строки увеличивается на единицу. В дальнейшем, если одну из этих строк потребуется модифицировать, она сначала будет скопирована (а счетчик ссылок оригинала, естественно, уменьшен) и только потом изменена, чтобы это не затрагивало остальные переменные.

Далее мы рассмотрим, какие проблемы могут возникнуть при использовании строк разного вида.

3.3.2. Хранение строковых литералов

Литералами называются значения, записываемые в программе буквально. В частности, строковые литералы в Delphi — это последовательности символов, заключенных в кавычки или записанных в виде ANSI-кодов с использованием префикса

#
.

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

Положим на форму пять кнопок и напишем следующие обработчики для нажатия на них (листинг 3.17, пример Constants на компакт-диске).

Листинг 3.17. Примеры работы со строковыми литералами

procedure TForm1.Button1Click(Sender: TObject);

var

 P: PChar;

begin

 P := 'Xest';

 P[0] := 'T'; { * }

 Label1.Caption := P;

end;

procedure TForm1.Buttom2Click(Sender: TObject);

var

 S: string;

 P: PChar;

begin

 S:= 'Xest';

 P := PChar(S);

 P[0] := 'T'; { * }

 Label1.Caption := P;

end;

procedure TForm1.Button3Click(Sender: TObject);

var

 S: string;

begin

 S := 'Xest';

 S[1] := 'T';

 Label1.Caption := S;

end;

procedure TForm1.Button4Click(Sender: TObject);

var

 S: ShortString;

begin

 S := 'Xest';

 S[1] := 'T';

 Label1.Caption := S;

end;

procedure TForm1.Button5Click(Sender: TObject);

var

 S: ShortString;

 P: PChar;

begin

 S := 'Xest';

 P := @S[1];

 P[0] := 'T';

 Label1.Caption := P;

end;
 

В

этом примере только нажатие на третью и четвертую кнопку приводит к появлению надписи Test. Первые два обработчика вызывают исключение Access violation в строках, отмеченных звездочками, а при нажатии пятой кнопки программа обычно работает без исключении (хотя в некоторых случаях оно все же может возникнуть), но к слову "Test" добавляется какой-то мусор. Разберемся, почему так происходит.

Встретив в первом обработчике литерал

'Xest'
и определив, что он относится к типу
PChar
, компилятор выделяет в подходящей области сегмента кода пять байтов (четыре значащих символа и один завершающий ноль), а в указатель
P
заносится адрес этого литерала. Сегмент кода доступен только для чтения, прав на его изменение система программе в целях безопасности не дает, поэтому попытка изменить то, что находится в этом сегменте, приводит к закономерному результату — выдаче сообщения "Access violation".

В обработчике второй кнопки происходит почти то же самое, с той лишь разницей. что для литерала выделяется на восемь байтов больше: т.к. в данном случае литерал имеет тип

AnsiString
, ему нужны еще 4 байта для хранения длины и 4 — для счетчика ссылок. В переменную
S
записывается указатель на этот литерал. Приводя эту переменную к типу
PChar
, мы, по сути, просто копируем этот указатель в переменную
P
, а дальше происходит то же самое — попытка изменить страницу памяти, доступную программе только для чтения с тем же самым результатом.

В третьем случае литерал, как и раньше, размещается в сегменте кода. Счетчик ссылок у таких литералов всегда равен -1 — это значение указывает менеджеру памяти, что это константа, которая не может быть изменена и память для которой не нужно освобождать. Поэтому при любой попытке изменить переменную, которой присвоен литерал, срабатывает механизм копирования по необходимости: для строки выделяется место в динамической памяти, затем значение литерала копируется в эту область, обновляется значение указателя

S
, а затем выполняется изменение копии, находящейся в динамической памяти. Так как эта память доступна и для чтения, и для записи, исключение не возникает, и все работает так, как и было задумано.

Поделиться:
Популярные книги

Черный Маг Императора 6

Герда Александр
6. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
7.00
рейтинг книги
Черный Маг Императора 6

Оцифрованный. Том 1

Дорничев Дмитрий
1. Линкор Михаил
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Оцифрованный. Том 1

Кодекс Охотника. Книга XIV

Винокуров Юрий
14. Кодекс Охотника
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Кодекс Охотника. Книга XIV

Штуцер и тесак

Дроздов Анатолий Федорович
1. Штуцер и тесак
Фантастика:
боевая фантастика
альтернативная история
8.78
рейтинг книги
Штуцер и тесак

Я снова граф. Книга XI

Дрейк Сириус
11. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Я снова граф. Книга XI

Болотник

Панченко Андрей Алексеевич
1. Болотник
Фантастика:
попаданцы
альтернативная история
6.50
рейтинг книги
Болотник

Кодекс Крови. Книга III

Борзых М.
3. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Крови. Книга III

Жестокая свадьба

Тоцка Тала
Любовные романы:
современные любовные романы
4.87
рейтинг книги
Жестокая свадьба

Стеллар. Трибут

Прокофьев Роман Юрьевич
2. Стеллар
Фантастика:
боевая фантастика
рпг
8.75
рейтинг книги
Стеллар. Трибут

Голодные игры

Коллинз Сьюзен
1. Голодные игры
Фантастика:
социально-философская фантастика
боевая фантастика
9.48
рейтинг книги
Голодные игры

Последняя Арена 8

Греков Сергей
8. Последняя Арена
Фантастика:
боевая фантастика
рпг
5.00
рейтинг книги
Последняя Арена 8

Черный маг императора 2

Герда Александр
2. Черный маг императора
Фантастика:
юмористическая фантастика
попаданцы
аниме
6.00
рейтинг книги
Черный маг императора 2

Последний Паладин

Саваровский Роман
1. Путь Паладина
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Последний Паладин

Измена. Свадьба дракона

Белова Екатерина
Любовные романы:
любовно-фантастические романы
эро литература
5.00
рейтинг книги
Измена. Свадьба дракона