pascalabcnet/InstallerSamples/BlockFileOfT/СправкаData/RefTSaving.html

134 lines
9.8 KiB
HTML
Raw Permalink Normal View History

2019-09-22 03:43:43 +03:00
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
.code_block {
background: #c0c0c0;
padding: 5px;
padding-right: 20px;
border: solid 1px black;
}
</style>
<script type="text/javascript">
function toggle_show(id) {
document.getElementById(id).style.display = document.getElementById(id).style.display == 'none' ? 'block' : 'none';
}
</script>
</head>
<body>
<font size="3"><a href="../Справка.html"><=</a></font><br>
<br>
<font size="5">Сохранение ссылочных типов в блочный файл.</font><br>
<hr />
<p onClick="toggle_show('decl')"><font size="4" color="008000" style="cursor: pointer">В чём проблема ссылочных типов</font></p>
<div id=decl style="display: none">
<p class=code_block>
<t style="margin-left: 00px">type </t>
<br><t style="margin-left: 10px">r1 = record </t>
<br><t style="margin-left: 20px">b: byte; </t>
<br><t style="margin-left: 20px">i: integer; </t>
<br><t style="margin-left: 20px">s: string; </t>
<br><t style="margin-left: 10px">end; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 00px">begin </t>
<br><t style="margin-left: 10px">var a: r1; </t>
<br><t style="margin-left: 10px">a.b := 5; </t>
<br><t style="margin-left: 10px">a.i := 12345; </t>
<br><t style="margin-left: 10px">a.s := 'abcdef'*10000;//Это 60 000 символов, ~120KB. А значит в записи никаким образом не поместилось бы </t>
<br><t style="margin-left: 00px">end. </t>
</p>
r1, byte и integer из этого примера - размерные типы (записи), а значит они хранят свои данные прямо в переменных.<br>
А string - ссылочный тип (класс). Это значит что в поле r1.s хранится только ссылка (особый указатель) на содержимое строки.<br>
<br>
То есть, в переменной "a" хранится три значения: byte, integer и ссылка.<br>
А содержимое строки хранится где-то в оперативной памяти, куда указывает эта ссылка.<br>
<br>
"BlockFileOf&ltT>" берёт содержимое переменных одним блоком памяти.<br>
Поэтому, если попытаться сохранить содержимое r1 в типизированный файл.<br>
(отключив защиту от дурака, запрещающую ссылочные типы)<br>
В файл сохранится значение ссылки, а не строки.<br>
<br>
Кроме того, ссылки отличаются от указателей тем, что они ссылаются на значение, которое может "плавать" в оперативной памяти.<br>
Точнее, сборщик мусора может двигать эти значения, для экономии места.<br>
Это значит что если сохранить запись с ссылкой в файл и сразу загрузить эту ссылку назад.<br>
Её значение может быть уже устаревшим.<br>
<hr />
</div>
<p onClick="toggle_show('io_basics')"><font size="4" color="008000" style="cursor: pointer">Размерные массивы и строки</font></p>
<div id=io_basics style="display: none">
Посмотрите в этот файл:<br>
C:\PABCWork.NET\Samples\BlockFileOfT\Сравнение скорости.pas<br>
Найдите там тип "ValueString255".<br>
На нём будут строиться дальнейшие обноснования:<br>
Этот тип представляет строку с фиксированной длинной, а точнее длиной в 255 символов.<br>
<br>
Первое, что видно - прямо перед объявлением типа стоит атрибут "StructLayout":<br>
"LayoutKind.Explicit" разрешает применять атрибут "FieldOffset" к полям.<br>
А "Size" позволяет явно указать сколько байт выделять под данную запись.<br>
Благодаря последнему - можно выделить место сразу под все 255 символов строки, не делая 255 полей с типом "char".<br>
<br>
Далее, в записи "ValueString255" есть всего 2 поля, "length" (длина) и "body" (тело, а точнее его начало)<br>
"length" это кол-во символов во всей строке. В данном случае не может быть больше 255 символов,<br>
поэтому достаточно 1 байта чтобы хранить любую возможную длину строки.<br>
А "body" это начало самогО содержимого строки.<br>
Вообще, поле "body" не так уж и нужно, но с ним будет проще, потому что если создать указатель на "body" -<br>
он сразу оказывается и указателем на содержимое строки, без каких-либо преобразований.<br>
<br>
Далее идут методы для преобразования между обычной строкой и нашей размерной.<br>
Я сделал их "operator explicit"-ами, потому что их вызов красивый и удобный.<br>
<br>
Смотрим в первый, преобразовывающий массив символов в размерную строку:<br>
<br>
Если выполнить "Result.length := a.Length" и передать массив длинной больше 255 символов -<br>
в этой строчке произойдёт переполнение и "Result.length" запонится мусором, поэтому сначала надо уменьшить значение до "MaxLength".<br>
<br>
Далее, если длина равна нулю - ничего больше делать не надо.<br>
В противном случае - используем процедуру "CopyMem".<br>
<br>
Насчёт того, как работает "CopyMem", можно написать целую диссертацию.<br>
Но главное, что надо знать вам: если попытаться получить указатель на элемент массива ("@a[n]") -<br>
получаем утечку памяти. Однако, если передать "a[n]" в "CopyMem" как var-параметр<br>
(что, по сути, тоже создаёт указатель на этот элемент массива),<br>
то всё в порядке.<br>
<br>
В данном случае мы копируем память начиная с нулевого элемента массива<br>
Вставляем её в "Result.body"<br>
И всего копируем "Result.length*2" байт (*2 потому что каждый символ занимает 2 байта в памяти)<br>
<br>
Преобразование из "string" в размерную строку работает также, там ничего интересного.<br>
У преобразования размерной строки в массив символов всего одна особенность:<br>
Теперь результат у нас ссылочный (массив), поэтому память под него нужно выделить вручную ("new char[...]").<br>
<br>
И последнее преобразование, из "ValueString255" в "string":<br>
А вот тут очень приятно вышло - у "string" есть конструктор который идеально подходит:<br>
Первый параметр это указатель на начало блока памяти содержащего символы. То есть "@s.body" и даже тип подходит без преобразований.<br>
Второй параметр - смещение начала. У нас символы начинаются прямо на "body", поэтому 0.<br>
И последний - количество символов.<br>
<br>
Последнее, что есть в данной записи - перегрузка "ToString". Это вообще не обязательный код,<br>
но с этой функцией размерная строка будет вести себя точно так же, как и обычная, если передать её во "Writeln".<br>
Также можно добавлять и другие свои методы в данный тип и даже сделать все те же методы, как и у ссылочных строк, или даже больше.<br>
<br>
Ну а размерные массивы ничем не отличаются в реализации.<br>
Можно даже сказать, что "ValueString255" это размерный массив символов, ничего от этого не изменится.<br>
<hr />
</div>
</body>
</html>