Страница 1 из 5

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

СообщениеДобавлено: 15.07.2013 09:42:11
arra
Доброго дня.
Сейчас пишу один проект, где много работы с динамическими массивами, в частности, много операций увеличения длины на единицу. Чтобы повысить читаемость кода решил я написать функцию, которой бы передавался по ссылке динамический массив, а она бы увеличивала его длину на единицу. Но проблема в том, что функция должна работать с массивами из любых элементов. Как это сделать, не соображу. Пробовал делать параметр функции array of variant, но тогда SetLength ругается на неправильный тип аргумента.
Подскажите, как это реализовать? Вроде простая вещь, и такой неожиданный затык.

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

СообщениеДобавлено: 15.07.2013 09:53:49
vada
Может так сойдет?
MyDinamicArray: List<Object>;

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

СообщениеДобавлено: 15.07.2013 10:56:01
arra
Не понял, что вы имели в виду. Можно пример?

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

СообщениеДобавлено: 15.07.2013 10:58:55
debi12345
Сейчас пишу один проект, где много работы с динамическими массивами, в частности, много операций увеличения длины на единицу. Чтобы повысить читаемость кода решил я написать функцию, которой бы передавался по ссылке динамический массив, а она бы увеличивала его длину на единицу.

Если таких фич нужно много, то можно попробовать DECAL (аналог STL под DELPHI). приаттачено.

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

СообщениеДобавлено: 15.07.2013 12:58:30
hovadur
debi12345 писал(а):приаттачено.

Вероятно, это очень старая версия, которая не работает в linux, и в 64-битном режиме. Вот более новая версия https://bitbucket.org/hovadur/decal - в ней я сделал работу с linux и в 64-битах. Она работает как в windows, linux lazarus, так и в delphi 7, delphi xe2.

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

СообщениеДобавлено: 15.07.2013 13:43:12
debi12345
hovadur, спасибо за ссылку !

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

СообщениеДобавлено: 15.07.2013 14:00:32
arra
Библиотеку посмотрю, спасибо.
Но в данном случае вопрос гораздо проще. Из-за такой ерунды прикручивать целую библиотеку не хочется. Должен же быть способ передавать в функцию массив из элементов любого типа! Сама SetLength же работает с любыми динамическими массивами.

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

СообщениеДобавлено: 15.07.2013 14:25:13
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.

у меня работает.

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

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

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

СообщениеДобавлено: 15.07.2013 15:22:35
arra
Debi12345, спасибо, идея интересная. Но мне нужно не совсем это - нужно не variant массив передавать, а массив integer, Word и массив из самописных структур. Если такой массив передать в описанную тобой процедуру, она сработает? Память выделится правильно?

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

СообщениеДобавлено: 15.07.2013 16:15:27
debi12345
Если такой массив передать в описанную тобой процедуру, она сработает

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

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

СообщениеДобавлено: 15.07.2013 16:45:03
arra
А как работает SetLength, когда я ему отдаю массив из самописных структур? Как-то же он просекает, что ему отдали и сколько памяти выделить?

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

СообщениеДобавлено: 15.07.2013 17:22:56
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, когда я ему отдаю массив из самописных структур? Как-то же он просекает, что ему отдали и сколько памяти выделить?
Потому что они одинаковые = можно точно узнать/предсказать/выделить размер и количесово.

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

СообщениеДобавлено: 17.07.2013 11:01:15
arra
Спасибо всем откликнувшимся. Но судя по всему это реализуемо гораздо сложнее, чем я думал и небольшое увеличение читаемости кода того не стоит.

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

СообщениеДобавлено: 17.07.2013 11:28:10
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-типа.