Динамический массив любого типа

Общие вопросы программирования, алгоритмы и т.п.

Модератор: Модераторы

arra
новенький
Сообщения: 27
Зарегистрирован: 30.03.2013 22:58:27

Динамический массив любого типа

Сообщение arra »

Доброго дня.
Сейчас пишу один проект, где много работы с динамическими массивами, в частности, много операций увеличения длины на единицу. Чтобы повысить читаемость кода решил я написать функцию, которой бы передавался по ссылке динамический массив, а она бы увеличивала его длину на единицу. Но проблема в том, что функция должна работать с массивами из любых элементов. Как это сделать, не соображу. Пробовал делать параметр функции array of variant, но тогда SetLength ругается на неправильный тип аргумента.
Подскажите, как это реализовать? Вроде простая вещь, и такой неожиданный затык.
Аватара пользователя
vada
энтузиаст
Сообщения: 691
Зарегистрирован: 14.02.2006 12:43:17

Сообщение vada »

Может так сойдет?
MyDinamicArray: List<Object>;
arra
новенький
Сообщения: 27
Зарегистрирован: 30.03.2013 22:58:27

Сообщение arra »

Не понял, что вы имели в виду. Можно пример?
Аватара пользователя
debi12345
долгожитель
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Сообщение debi12345 »

Сейчас пишу один проект, где много работы с динамическими массивами, в частности, много операций увеличения длины на единицу. Чтобы повысить читаемость кода решил я написать функцию, которой бы передавался по ссылке динамический массив, а она бы увеличивала его длину на единицу.

Если таких фич нужно много, то можно попробовать DECAL (аналог STL под DELPHI). приаттачено.
Вложения
decal.rar
(220.52 КБ) 558 скачиваний
hovadur
постоялец
Сообщения: 116
Зарегистрирован: 31.01.2013 15:50:41

Сообщение hovadur »

debi12345 писал(а):приаттачено.

Вероятно, это очень старая версия, которая не работает в linux, и в 64-битном режиме. Вот более новая версия https://bitbucket.org/hovadur/decal - в ней я сделал работу с linux и в 64-битах. Она работает как в windows, linux lazarus, так и в delphi 7, delphi xe2.
Аватара пользователя
debi12345
долгожитель
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Сообщение debi12345 »

hovadur, спасибо за ссылку !
arra
новенький
Сообщения: 27
Зарегистрирован: 30.03.2013 22:58:27

Сообщение arra »

Библиотеку посмотрю, спасибо.
Но в данном случае вопрос гораздо проще. Из-за такой ерунды прикручивать целую библиотеку не хочется. Должен же быть способ передавать в функцию массив из элементов любого типа! Сама SetLength же работает с любыми динамическими массивами.
Аватара пользователя
debi12345
долгожитель
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Сообщение debi12345 »

Кажется Вы наткнулись на одну хитрую багофичу компилятора (с путаницей динамических и открытых массивоа в параметрах функций). Попробуйте следущее:

Код: Выделить всё

program test;
{$mode objfpc}

uses
  variants;

type
  vararty = array of variant;

procedure addelem(var arr: vararty; elem: variant);
begin
  setlength(arr,length(arr)+1);
  arr[high(arr)] := elem;   
end;

var
  a1:  vararty;

begin
  addelem(a1,2);
  addelem(a1,1.23);
  addelem(a1,'test'); 
end.

у меня работает.
zub
долгожитель
Сообщения: 2890
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

>>Должен же быть способ передавать в функцию массив из элементов любого типа! Сама SetLength же работает с любыми динамическими массивами.
array of variant и "Динамический массив любого типа" это разные вещи.
То что SetLength работает - это внутренняя процедура компилятора, самому такую объявить не получится. SetLength кроме выделения памяти под новый эдемент должен его проинициализировать (в случае массива сложных типов), т.е. он должен знать о типе данных лежащих в массиве.
Поэтому придется написать несколько overload процедур для всех нужных типов массивов или воспользоваться генериками - готовая реализация tvector есть в пакете fpc-stl
arra
новенький
Сообщения: 27
Зарегистрирован: 30.03.2013 22:58:27

Сообщение arra »

Debi12345, спасибо, идея интересная. Но мне нужно не совсем это - нужно не variant массив передавать, а массив integer, Word и массив из самописных структур. Если такой массив передать в описанную тобой процедуру, она сработает? Память выделится правильно?
Аватара пользователя
debi12345
долгожитель
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Сообщение debi12345 »

Если такой массив передать в описанную тобой процедуру, она сработает

С простыми типами работает. Сруктура как "variant" - не пробовал (подозреваю проблемы -потому что Variant-RTL делает провеки на vt-тип, ессно неизвестный для кастомных структур). Если не проканает, то придется либо работатьс массвом указателей (=возня с диманической памятью), либо массивом оф TObject (rак делает DCALC).
Или запаковать струтурный тип напрме в строку и внутри ее распарсивать. Или эмулировать RECORD в виде массива на базе "variant" (VarCreateArray, VarArrayRedim, VarArrayPut,..) - записывая в один из индексов этого массива опознавательный идентификатор структуры,а в остальные индексы - значения полей "структуры ").
arra
новенький
Сообщения: 27
Зарегистрирован: 30.03.2013 22:58:27

Сообщение arra »

А как работает SetLength, когда я ему отдаю массив из самописных структур? Как-то же он просекает, что ему отдали и сколько памяти выделить?
Аватара пользователя
debi12345
долгожитель
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Сообщение debi12345 »

Вариант с засовываниеv RECORD-типа "chmorecty" в бинарный Variant-тип
(с функцией), и уже его в "vararty = array of variant " :

Код: Выделить всё

program test;
{$mode objfpc}{$h+}


uses
  variants,sysutils;

type

  vararty = array of variant;
  chmorecty = packed record
    int_val: integer;
    str_val: shortstring;
  end;
  pchmorecty = ^chmorecty;


procedure addelem(var arr: vararty; elem: variant);
begin
  if VarIsArray(elem) then begin
    with pchmorecty(VarArrayLock(elem))^ do begin
      writeln('added record: {' + inttostr(int_val) + ',' + str_val +'}');
      VarArrayUnlock(elem);
    end;
  end else begin
    writeln('added atomic: ' + varToStr(elem));
  end;
  setlength(arr,length(arr)+1);
  arr[high(arr)] := elem;   
end;

procedure addchmo(arr: vararty; recarr: variant; var chmorec: chmorecty);
var
  chmorecptr: pchmorecty;
  sz: integer;
begin
  sz:= sizeof(chmorecty);
  chmorecptr := VarArrayLock(recarr); 
  Move(chmorec,chmorecptr^,sz);
  VarArrayUnlock(recarr);
  addelem(arr,recarr); 
end;


var
  vardata_arr:  vararty;
  chmoarr: variant;
  chmorec: chmorecty;

begin
  chmoarr:= vararraycreate([0,sizeof(chmorecty)],varByte);

  addelem(vardata_arr,2);
  addelem(vardata_arr,1.23);
  addelem(vardata_arr,'test'); 

  chmorec.int_val:= 1;
    chmorec.str_val:= 'one';
      addchmo(vardata_arr,chmoarr,chmorec);

  chmorec.int_val:= 100;
    chmorec.str_val:= 'hundred';
      addchmo(vardata_arr,chmoarr,chmorec);

  varclear(chmoarr);

end.



Добавлено спустя 2 часа 57 минут 12 секунд:
А как работает SetLength, когда я ему отдаю массив из самописных структур? Как-то же он просекает, что ему отдали и сколько памяти выделить?
Потому что они одинаковые = можно точно узнать/предсказать/выделить размер и количесово.
arra
новенький
Сообщения: 27
Зарегистрирован: 30.03.2013 22:58:27

Сообщение arra »

Спасибо всем откликнувшимся. Но судя по всему это реализуемо гораздо сложнее, чем я думал и небольшое увеличение читаемости кода того не стоит.
Аватара пользователя
debi12345
долгожитель
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Сообщение debi12345 »

Если вынести методы засовывания рекордов в массивы вариантов ("addchmo(arr: vararty; recarr: variant; var chmorec: chmorecty)" в примере) в отдельный модуль,то все будет очень просто :

Код: Выделить всё

chmorec.int_val:= 1; 
    chmorec.str_val:= 'one';
      addchmo(vardata_arr,chmoarr,chmorec);


Добавлено спустя 7 минут 11 секунд:
Конкретно Ваша задача решается именно использованием VARIANT-типа.
Ответить