Dynamiczna tablica obiektów

0

mam dynamiczną tablicę obiektów,
Tworzę obiekt TDokument, wyepłniam do i dodaję do tablicy. I w tym momencie on w tablicy jest. Ale jak przejdzie linię FreeAndNil(kolejnyDokument) to dane z tablicy znikają (ale nie wszystkie).
Pewnie trzeba to robić jakoś inaczej?

 wybraneDokumenty: array of TDokument;



          SetLength(wybraneDokumenty, Length(wybraneDokumenty) + 1);
          kolejnyDokument := TDokument.Create();
          kolejnyDokument.idDokumentuObce := FLogikaDokumentyPowiazane.kbmZnalezioneDokumentyIdDokumentu.Value; //ID_DOK
          kolejnyDokument.typDokumentu := FLogikaDokumentyPowiazane.kbmZnalezioneDokumentyTypDokumentu.Value; //DOK
          kolejnyDokument.idProgramu := 1;
          kolejnyDokument.idAutora := gZalogowanyId;
          kolejnyDokument.nrDokumentu := StrToInt(FLogikaDokumentyPowiazane.kbmZnalezioneDokumentyNrDokumentu.Value); //NR_DOK
          kolejnyDokument.nrPojazdu := FLogikaDokumentyPowiazane.kbmZnalezioneDokumentyNrPojazdu.Value; //NR_POJAZDU
          kolejnyDokument.rokDokumentu := YearOf(FLogikaDokumentyPowiazane.kbmZnalezioneDokumentyDataDokumentu.Value); //ROK_DOK
          wybraneDokumenty[Length(wybraneDokumenty)-1] := kolejnyDokument;


          FreeAndNil(kolejnyDokument);
0

Zależy co chcesz zrobić. Jak chcesz zwolnić utworzony "kolejnyDokument" dodany do końca tablicy "wybraneDokumenty" to robisz tak:

FreeAndNil(kolejnyDokument);
wybraneDokumenty[Length(wybraneDokumenty)-1] := nil; //bo w wierszu wyżej zwolniłeś ostatni element tablicy "wybraneDokumenty"
SetLength(wybraneDokumenty, Length(wybraneDokumenty) -1);//opcjonalnie usuwasz ostatni element, bo jest "nil" 

A jeśli ostatni element tablicy "wybraneDokumenty" (który wskazuje na obiekt "kolejnyDokument") ma być używany gdzieś dalej, to nie możesz zwalniać obiektu "kolejnyDokument", bo tym samym zwolnisz obiekt, na który wskazuje ostatni element tablicy "wybraneDokumenty", mimo, że pozostanie jako "ślepy" wskaźnik na zwolniony obiekt "kolejnyDokument".

0

ten kolejny dokument ma pozostać w tablicy.
I ja to robię w pętli tworząc wiele dokumentów, to żaden z nich nie zostanie zwolniony?
Wiele razy Create a ani razu Free.

0

To musisz stworzyć jego kopie!
Ogólnie to nie wiem co chcesz zrobic, ale można tez po prostu nie zwalniać 'kolejnyDokument' nie widziałem kodu więc ciężko na 100% powiedzieć.

0

Właśnie myślałem że dodając do tablicy tab będzie jego kopia więc mogę zwolnić ten utworzony dokument.
Ale myślę że do tablicy jest przekazywany tylko wskaźnik na obiekt a nie cała jego zawartość, prawda?

0

Jak przypisujesz do ostatniego elementu tablicy "wybraneDokumenty" wskaźnik na kolejny utworzony obiekt "kolejnyDokument", to nie zwalniasz "kolejnyDokument", bo jak pisałem wcześniej, elementy tablicy staną się (ślepymi) wskaźnikami na nieistniejące już obiekty.
Dopiero gdy już nie potrzebujesz utworzonych obiektów, zwalniasz je wykorzystując wskaźniki do nich którymi są właśnie te elementy tablicy:

 For i := 0 to length(wybraneDokumenty) - 1 do
  FreeAndNil(wybraneDokumenty[i]);
SetLength(wybraneDokumenty, 0);
2

@Pele2 - bardzo dziwnie zabierasz się za ten problem; Po co używasz do tego macierzy dynamicznej? Do przechowywania listy obiektów są już gotowe kontenery, jak choćby TObjectList, już nie wspominając o liście generycznej;

Jeśli już koniecznie chcesz bawić się tablicami to rób to sensownie; Po pierwsze zadeklaruj sobie macierz dla dokumentów, a po drugie - licznik elementów jako zwykła liczba całkowita:

type
  TDocumentsArr = array of TDocument;

{...}

var
  arrDocuments: TDocumentsArr;  // macierz obiektów
  intDocumentsCnt: Integer;     // liczba elementów macierzy

Przy dodawaniu nowego obiektu do macierzy, najpierw korzystając z lokalnej zmiennej utwórz obiekt i go uzupełnij (jeśli to konieczne), następnie powiększ macierz o jeden element, przepisz referencję z lokalnej zmiennej do ostatniego pola macierzy (używając licznika), a na koniec inkrementuj licznik:

var
  dcmNew: TDocument;
begin
  dcmNew := TDocument.Create();
  // tu uzupełnij dane dokumentu

  SetLength(arrDocuments, intDocumentsCnt + 1);
  arrDocuments[intDocumentsCnt] := dcmNew;

  Inc(intDocumentsCnt);

  // nie uruchamiaj dcmNew.Free!
end;

No i tyle - żadnych zabaw z Length;

Kolejna rzecz - FreeAndNil używa się w takim przypadku, gdy referencja do instancji klasy koniecznie ma wskazywać na Nil, aby dało się sprawdzić czy obiekt istnieje, czy nie; Przydaje się to tylko i wyłącznie wtedy, gdy mamy np. globalną zmienną lub pole klasy, które w całym swoim czasie życia może przechowywać wiele obiektów, kolejno tworzonych i zwalnianych z pamięci; Ty tego nie potrzebujesz, więc zwykłe Free w zypełności wystarczy;


Wskazówka nr 1

Naucz się sensownie formatować kod i stosować się do przyjętej konwencji nazewnictwa, bo Twój kod czyta się beznadziejnie (to i tak delikatnie ujęte); Nie dość, że używasz polskich identyfikatorów, to jeszcze notacji węgierskiej; Serio, notacji węgierskiej dla właściwości? Ona przewidziana jest dla lokalnych zmiennych (ew. globalnych), ale tylko do tego; A to:

FLogikaDokumentyPowiazane.kbmZnalezioneDokumentyTypDokumentu.Value

To nawet po polsku nie jest;

Wskazówka nr 2

wybraneDokumenty[Length(wybraneDokumenty) - 1]

To samo można zrobić krócej (bez odejmowania) za pomocą High:

wybraneDokumenty[High(wybraneDokumenty)]

Ale i tak stosuj się do tego co opisałem wcześniej, czyli zapamiętaj liczbę elementów w dodatkowej zmiennej.

1 użytkowników online, w tym zalogowanych: 0, gości: 1