Вопрос по указателям для типа record (Delphi)

dimon72

Ковыряюсь тут с одной прогой. Работаю с записями. Понадобилось очищать все поля записи одним махом. Задумался как реализовать. Напрямую, видимо, не получается. Начал делать через указатели. Получилось. Выяснилась одна неприятная особенность: когда работаешь с фактическими записями, то они всегда нормально инициализируются Delphi, наподобие глобальных переменных. Если работаешь с указателем на запись, то получается, что до присвоения какому-либо полю значения оно не определено. Всё вроде понятно, так и должно быть, очевидно. Только вот незадача: прога была ориентирована на негласную инициализацию, а тут заглючила, поскольку поля записей стали вести себя наподобие локальных переменных.
--------------------------------------------------------------------------------------------------------
Type
TMyRec = Record
a: integer;
b: integer;
c: integer;
d: array of integer;
end;
var
PRec: ^TMyRec;
new(PRec);
//пока полям не присвоены числа, их значения не определены!
With PRec^ do
begin
a:=100; b:=200; c:=300;
SetLength(d,5);
d[0]:=1; d[1]:=2; d[2]:=3; d[3]:=4; d[4]:=5;
end;
dispose(PRec);
-------------------------------------------------------------------------------------------------------
Вопрос: как мне инициализировать поля записей, когда они используются через указатель, не обращаясь отдельно к каждому полю?

Corrector

первоначальная задача, насколько я понимаю - очистить все поля записи одним махом. Можно это сделать через вариантные массивы

TMyRec = record
case Integer of
1: (a1: Integer;
a2: Integer;
a3: Integer);
2: (RecArr: array [0..3*SizeOf(Integer) - 1] of byte);
end;

поле RecArr хранится по тому же адресу, что и a1, a2,a3 - можно обнулить массив и обнулятся a1,a2,a3

SPARTAK3959

Если тебе их нужно инициализировать нулем, то используй
fillchar(prec^,sizeof(prec^0);

Если тебе их нужно инициализировать не нулем, то нужно переходить на object (пока виртуальные методы не используются, он ведет себя как record):
type
TMyRec=object
a:integer;
b:integer;
c:integer;
d:array of integer;
constructor init;
destructor done;
end;
constructor TMyRec.init;
begin
a:=2;
b:=1;
c:=0;
d:=nil;
end;
destructor TMyRec.done;
begin
setlength(d,0);
end;
var
rec:^TMyRec;
begin
new(rec,init);
writeln(rec^.a,',',rec^.b,',',rec^.c);
dispose(rec,done);
end.

dimon72

Хорошо, а если в записи присутствуют разнородные данные, в том числе строки, массивы строк и др.?

dimon72

Попробую, спасибо.

dimon72

Да, ещё: если методом fillchar заполнить выделенную память нулями, то как поведут себя поля с типом, отличным от integer? Как проще всего проинициализировать строковые переменные в записи, чтобы там не оказался "мусор"?

Corrector

если использовать строки с фиксированной длиной, то в записи выделяется память для них, ссылки не используются
если используются разнородные данные, содержащие ссылки, то наверно, вместо записей надо использовать классы с published-секцией и получить информацию о количестве и типах полей в runtime

SPARTAK3959

На сколько я знаю, типы вещественных данных при этом инициализируются нулем. Строки переменной длины инициализируются nil, что для паскаля равносильно пустой строке. Вот только с variant будут проблемы и, возможно, с множествами.

dimon72

Попробовал через fillchar на разных типах полей (целое, строка, массив строк, булев тип). Всё ok.
С конструктором-деструктором инициализация тоже хороший вариант. В общем, спасибо други!
Оставить комментарий
Имя или ник:
Комментарий: