Newsgroup: it.comp.lang.delphi
Titolo: "Scalare" array

Salve,
ho un array statico, ma "dinamico" (non mi so spiegatre bene lo so...) dove
creo oggetti in base alla richiesta.
Es: l'array di una "MyClass" che va da 1 a 1000. Quando necessario alloco la
memoria per l'n-esima posizione con il componente necessario:
ArrayMyClass[10].Memo1:=Tmemo.create;
Quando non necessario (perchè vecchio) lo libero (.free) e il la posizione
dell'array non può più essere usata.
Questo è un limite perchè si potrebbe raggiungere la 1000-esima posizione in
breve tempo, anche liberandone molti prima...
Esiste un modo, una procedura predefinita che mi permetta di far scalare
(anche cancellando) le posizioni dell'array nelle prime disponibili?
Mentre scrivo capisco che probabilmente non mi capirei neanche da solo e
probabilmente l'unica soluzione sarebbe quella che avevo in mente e cioè
quella di fare un "for to do" alla distruzione dei dati "vecchi" in modo da
copiare e scalare di posizione quelli utili con quelli "medi-vuoti".
Non mi stupirebbe che non ricevessi alcuna risposta :p
Grazie :-p

 dove creo oggetti in base alla richiesta.
dò per scontato che conosci già l'esistenza di TList (o derivati), che fa 
tutto ciò in automatico...
-- 
Mauro Falzari 
   [ 
http://digilander.libero.it/mauro.falzari
 ]
 
 "Se guardi nell'abisso, anche l'abisso guarda in te." 
   (Friedrich Nietzsche)

 che fa tutto ciò in automatico...
Ne ho sentito parlare, ma non l'ho mai usato. In realtà non ho neanche ben
capito (o meglio non ricordo più granchè) di cosa si tratti precisamente...

 tratti precisamente...
O meglio, da quel che ricordo dovrebbe essere un "array dinamico"... ma ben
più lento di uno statico.
Non mi è mai capitato di usarlo però e non so bene come fare... (è poi così
più lento di uno statico?)

 capito (o meglio non ricordo più granchè) di cosa si tratti 
precisamente...
posso provare a darti degli spunti da cui partire. 
TList serve per mantenere una lista di puntatori: fornisce già pronti dei 
metodi per aggiungerli, cancellarli, inserirli, cercarli, oppure per 
esempio dei metodi per svuotare la lista o riordinarla.
Un piccolo esempio con i puntatori, tanto per cominciare:
type
  TGeneric = record
    ID: Integer;
    Name: string
  end;
  PGeneric = ^TGeneric;
procedure Test1;
var
  L: TList;
  G: PGeneric;
  i: Integer;
begin
  L:= TList.Create;
  try
    New(G);
    try
      G^.ID:= 123456789;
      i:= L.Add(G);
      PGeneric(L[i])^.Name:= 'QDI KuDoz';
      ShowMessage('L ha ' + IntToStr(L.Count) + ' elementi: ' +
        #10#13#10#13'elemento n. ' + IntToStr(i) +
        #10#13'ID = ' + IntToStr(PGeneric(L[i])^.ID) +
        #10#13'Name  = ' + G^.Name);
    finally
      Dispose(G)
    end
  finally
    L.Free;
  end;
end;
E siccome gli oggetti sono puntatori, un analogo esempio con gli oggetti 
(a te scoprire le differenze):
procedure Test2;
var
  L: TList;
  GO: TGenericObj;
  i: Integer;
begin
  L:= TList.Create;
  try
    GO:= TGenericObj.Create;
    try
      GO.ID:= 666;
      i:= L.Add(GO);
      TGenericObj(L[i]).Name:= 'AMD Barton';
      ShowMessage('L ha ' + IntToStr(L.Count) + ' elementi: ' +
        #10#13#10#13'elemento n. ' + IntToStr(i) +
        #10#13'ID = ' + IntToStr(TGenericObj(L[i]).ID) +
        #10#13'Name  = ' + GO.Name);
    finally
      GO.Free;
    end
  finally
    L.Free;
  end;
end;
A parte il fatto che non c'è nessun controllo sui tipi degli elementi che 
fanno parte alla lista (si potrebbe per esempio aggungere tranquillamente 
un puntatore a un intero), c'è un altro grosso problema: quando la lista 
viene distrutta, non rilascia la memoria allocata per i puntatori o gli 
oggetti contenuti (infatti dobbiamo richiamare "manualmente" Free o 
Dispose, a seconda dei casi).
L'esempio successivo dovrebbe mostrare come ovviare in modo relativamente 
semplice a questi problemi.
Invece di derivare da TList, deriviamo da TObjectList, che è una lista che 
"possiede" i suoi oggetti. Infatti quando viene chiamato il distruttore 
della lista, prima essa li distrugge (come si vede chiaramente 
nell'esempio).
Inoltre c'è un effetto molto importante, la lista è ora (quasi) type-safe, 
cioè si possono aggiungere solo oggetti di un certo tipo e verranno 
restituiti solo oggetti di quello stesso tipo.
Per farlo girare, questo codice va messo nella sezione implementation di 
una form, con l'evento OnCreate opportunamente collegato.
Per ulteriori commenti, ti rimando alla fine del post.
//**************************************************
uses
  Contnrs;
type
  TProduct = class
  private
    FID: Integer;
    FName: string;
  public
    destructor Destroy; override;
    property ID: Integer read FID write FID;
    property Name: string read FName write FName;
  end;
  TProducts = class(TObjectList)
  protected
    function GetProduct(const Index: Integer): TProduct;
    procedure SetProduct(const Index: Integer; Item: TProduct);
  public
    function Add(Item: TProduct): Integer;
    procedure Insert(const Index: Integer; Item: TProduct);
    property Objects[const Index: Integer]: TProduct read GetProduct write 
SetProduct; default;
  end;
{ TProduct }
destructor TProduct.Destroy;
begin
  Writeln('Messaggio generato dal distruttore di un ' + ClassName);
  inherited Destroy;
end;
{ TProducts }
function TProducts.Add(Item: TProduct): Integer;
begin
  Result:= inherited Add(Item);
end;
function TProducts.GetProduct(const Index: Integer): TProduct;
begin
  Result:= TProduct(inherited GetItem(Index))
end;
procedure TProducts.Insert(const Index: Integer; Item: TProduct);
begin
  inherited Insert(Index, Item)
end;
procedure TProducts.SetProduct(const Index: Integer; Item: TProduct);
begin
  inherited SetItem(Index, Item)
end;
{$APPTYPE CONSOLE}
procedure TForm1.FormCreate(Sender: TObject);
var
  Product: TProduct;
  ProductList: TProducts;
  Index: Integer;
  procedure _WriteListAdded(const i: Integer);
  begin
    Writeln('Aggiunto l''elemento di indice ' + IntToStr(i));
  end;
  procedure _WriteListItem(const i: Integer);
  begin
    Writeln('Contenuto dell''elemento di indice ' + IntToStr(i) +':');
    Writeln(#9'Product.ID = '#9 + IntToStr(ProductList[Index].ID));
    Writeln(#9'Product.Name = '#9 + ProductList[Index].Name);
  end;
  procedure _WriteListCount;
  begin
    Writeln(#32'La lista contiene ' + IntToStr(ProductList.Count) + ' 
elementi');
    Writeln;
  end;
begin
  ProductList:= TProducts.Create;
  try
    Product:= TProduct.Create;
    Index:= ProductList.Add(Product);
    _WriteListAdded(Index);
    Product.ID:= 111111111;
    ProductList[Index].Name:= 'JACK LO SQUARTATORE';
    _WriteListItem(Index);
    _WriteListCount;
    Product:= TProduct.Create;
    Index:= ProductList.Add(Product);
    _WriteListAdded(Index);
    Product.ID:= 2222;
    ProductList[Index].Name:= 'IL LUPO MANNARO';
    _WriteListItem(Index);
    _WriteListCount;
    Product:= TProduct.Create;
    Index:= ProductList.Add(Product);
    _WriteListAdded(Index);
    Product.ID:= 333;
    ProductList[Index].Name:= 'FINAL DOOM: HELL ON EARTH';
    _WriteListItem(Index);
    _WriteListCount;
    Product:= ProductList[1];
    Index:= ProductList.Remove(Product);
    Writeln('Cancellato l''elemento di indice ' + IntToStr(Index));
    _WriteListCount;
    for Index:= 0 to Pred(ProductList.Count) do
      _WriteListItem(Index);
  finally
    Writeln;
    ProductList.Free;
  end;
end;
//**********************************************************
A questo punto ci sarebbero altri problemucci da risolvere, per esempio: 
-posso aggiungere ancora oggetti di altri tipi, manipolando ProductList 
come se fosse una TList, ecco che
    o:= TObject.Create;
    TList(ProductList)[1]:= o;
è perfettamente lecito;
-non c'è nessun modo di controllare quando un oggetto della lista diventa 
nil;
-non c'è nessun modo per evitare che la lista abbia sempre e solo oggetti 
differenti l'uno dall'altro, evitare cioè che si possa fare:
    ProductList[1]:= ProductList[2]
Per ovviare a questi problemi ci sono le Collection: TCollection e 
TCollectionItem.


 end;
-- 


Mauro Falzari wrote:
[CUT]
Grazie mille, ora me lo studio per bene, con calma, sperando di non fare
troppi pastrocchi alla struttura già creata ^_^
Ciao

I/O scriveva fra l'altro:

La VCL usa le TList per (quasi) tutto (liste di classi registrate,
componenti sulle form, form sullo schermo, etc...).
Se vuoi iniziare con una dimensione diversa da zero, imposta la prop.
Capacity prima di aggiungere elementi alla lista. Vedi anche
TObjectList.
Saluti
Paolo Arosio
--
"La dimostrazione dell'esistenza di specie intelligenti nell'universo
 e' che non ci vengono a trovare"

 TObjectList.
grazie delle dritte anche a te :-)

 troppi pastrocchi alla struttura già creata ^_^
no, no, falli pure che è da quelli che si impara


 troppi pastrocchi alla struttura già creata ^_^
se posso darti un consiglio, prima di passare al tuo caso pratico, cerca di 
crearti un esempio "generico" (e funzionante), di quello che vorresti 
ottenere.
