egzemplarz klasy zwalnia pamiec jak zmienna lokalna

0

Witam
Mam takie pytanie, mianowicie:
1Tworze sobie jakis record w delphi
2W jakiejs funkcji/procedurze deklaruje dynamicznie sobie egzemplarz rekordu np:

var a:Trecord;

teraz jego definicja:

begin
  new(a); 
  a^.p := 3; {...}

Powyzsza funcja wykona sie zalozmy 5 razy, po wyjsciu z takiej funkcji moge sie odwolywac do utworzonych egzemplarzy rekordu Trec poprzez np wzkazniki.

A teraz mam klase, tworze dynamicznie jej egzemplarze znowu w jakiejs funkcji
np:

function x....
var a:Tklasa;
begin
a:=Tklasa.create; {...}

Po wykonaniu owej funkcji roznica jest taka ze wszystkie wzkazniki do egzemplarzy klasy Tklasa wzkazuja jedna pamiec - ostatnio utworzonego egzemplarza. Oznacza to że egzemplarze sie nadpisuja czyli po zakonczeniu funkci pamiec dla zmiennej lokalnej 'a' zostaje zwolniona, i tu moje pytanie dlaczego ? I jak temu mozna zapobiec ?
Dlaczego egzemplarz rekordu zachowuje sie inaczej niz egz. klasy?
Będe bardzo wdzięczny za odpowiedz. Pozdrawiam

0
pixi napisał(a)

Po wykonaniu owej funkcji roznica jest taka ze wszystkie wzkazniki do egzemplarzy klasy Tklasa wzkazuja jedna pamiec - ostatnio utworzonego egzemplarza.

Wcale nie.

function A():TLabel;
begin
result:=TLabel.Create(nil);
end;

procedure TForm1.FormShow(Sender: TObject);
var X,Y:TLabel;
begin
X:=A();
Y:=A();
Caption:=IntToHex(Integer(X), 8)+' '+IntToHex(Integer(Y), 8);
Y.Free;
X.Free;
end;

Prosty kodzik, funkcja tworzy obiekt klasy TLabel. Adresy dwóch takich obiektów wyświetlam w nagłówku okna. Wartości są różne. Prawdopodobnie masz gdzieś indziej błąd w kodzie.

0
Szczawik napisał(a)
function A():TLabel;
begin
result:=TLabel.Create(nil);
end;

procedure TForm1.FormShow(Sender: TObject);
var X,Y:TLabel;
begin
X:=A();
Y:=A();
Caption:=IntToHex(Integer(X), 8)+' '+IntToHex(Integer(Y), 8);
Y.Free;
X.Free;
end;

No dobra to teraz jak procedura FormShow się zakończy to już odwołać się do X,Y nie można. A chodzi mi o to by te egzemplarze (X,Y) były dalej.

0

zmienne deklarowane lokalnie przechowywane są na stosie: proste typy bezpośrednio, natomiat tablice dynamiczne, stringi i instancje klas jako wskaźniki do nich. Instancja klasy istnieje w pamięci (na stercie), ale po zakończeniu procedury wskaźnik do niej jest zdejmowany ze stosu i nie można się już dalej do niej odwołać, chyba że przekażesz wskaźnik na zewnątrz procedury/funkcji.

typ Trecord to rekord czy wskaźnik do niego?

0
Luc napisał(a)

zmienne deklarowane lokalnie przechowywane są na stosie: proste typy bezpośrednio, natomiat tablice dynamiczne, stringi i instancje klas jako wskaźniki do nich. Instancja klasy istnieje w pamięci (na stercie), ale po zakończeniu procedury wskaźnik do niej jest zdejmowany ze stosu i nie można się już dalej do niej odwołać, chyba że przekażesz wskaźnik na zewnątrz procedury/funkcji.

No własnie do utowrzonego dynamicznie egzemplarza klasy "podpinam" globalny wzkaźniki, tylko co z tego jeśli egzemplarze zwalniaja pamiec

Luc napisał(a)

typ Trecord to rekord czy wskaźnik do niego?

To rekord

moze jakis przyklad:

type
  Pelem = ^Telem;
  Telem = class
    prev : Pelem;
    next : Pelem;
    key  : integer;
    constructor create;
    destructor destroy;
    end;
{...}
var
  Head,x:Pelem; i:integer; //zmienne globalne
{...}
procedure inicjuj(_wart:integer);
var v:Telem;
begin
   v := Telem.create;
   v.key:= _wart;
   Head := @v;
end;
procedure dodaj(_wart:integer);
var c:Telem;
begin
  c := Telem.create;
  Head.prev := @c;
  c.next := Head;
  Head := @c;
end;
{...}
begin
  inicjuj(9);
  dodaj(3);
  dodaj(6);
  dodaj(5);
  // teraz proba wypisania np 2 elementu ktory zostal utworzony dynamicznie w procedurze dodaj
  writeln((Head.next).key); // bład odczytu wzkaznik pokazuje inna pamiec w ktorej juz niema tego egzempl.
{...}

P.S. Kod działa poprawnie jeśli zamiast klasy używam rekordu, (który zresztą jest autorstwa mojego wykładowcy)
P.S.S. Jest to symulacja działania Listy

0

Zmienne odnoszące się do instancji klas są już wskaźnikami, więc nie ma sensu tworzyć 'wskaźników do wskaźników':
Telem będzie wskazywał na miejsce na stercie (instancje klasy)
Pelem będzie wskazywał na wskaźnik Telem, znajdujący się na stosie (skąd zostanie usunięty po zakończeniu procedury).

Poza tym, jeśli lokalnie tworzysz obiekty kilkakrotnie, nie zwalniając ich potem doprowadzasz do wycieków pamięci.

Informacji o listach poszukaj w arkykułach w dziale Delphi

0
Luc napisał(a)

Zmienne odnoszące się do instancji klas są już wskaźnikami, więc nie ma sensu tworzyć 'wskaźników do wskaźników':

Czyli załóżmy var v:Telem; c:Pelem;
czyli v <- jest wzkaźnikiem, to jak pobrać jego adres i zapisać to do c ?
bo przeciez c := @v // da nam adres do wzkaznika a to bez sensu.
natomiast c := v jest 'niekompilowalne'

0

zamiast wskaźnika typowanego wystarczy zwykły Pointer

0

Zrobiłem tak:

type
  Pelem = ^Telem;
  Telem = class
    prev : Pelem;
    next : Pelem;
    key  : integer;
    end;
{...}
var
  x:Pelem; H:Pointer;  //zmienne globalne
{...}
procedure inicjuj(_wart:integer);
var v:Telem;
begin
   v := Telem.create;
   v.key:= _wart;
   H := v;
end;
procedure dodaj(_wart:integer);
var c:Telem;
begin
  c := Telem.create;
  c.key := _wart;
  c.next := H;
  H := c;
end;
{...}
begin
  inicjuj(9);
  dodaj(3);
  dodaj(6);
  dodaj(5);
  x:=H; // czyli wzkaznik typowy = adres klasy
  writeln(x.key) //pokazuje wartosc z kosmosu
  writeln((Head.next).key); // i tu dalej są jaja program sie sypie
{...}

?

0

wywal te Pelemy w kosmos, bo do niczego ich nie potrzebujesz. Nie deklaruje się "adresu do adresu", bo będzie pokazywał na cholerawieco.
Możesz posłużyć się samymi Telemami bo to też są wskaźniki.

0
Luc napisał(a)

wywal te Pelemy w kosmos, bo do niczego ich nie potrzebujesz. Nie deklaruje się "adresu do adresu", bo będzie pokazywał na cholerawieco.
Możesz posłużyć się samymi Telemami bo to też są wskaźniki.

Jarze, jarze, jarze ! Ale ze mnie kloc, ale juz skapowałem Dzięki Luc za cierpliwość i odpowiedź ! :-D

0

jak by ktos byl ciekaw:

program Lista;
uses
  SysUtils;
type
  Pelem = ^Telem;
  Telem = class
    prev : Telem;
    next : Telem;
    key  : integer;
    constructor create;
    destructor destroy;
    end;
constructor Telem.create;
begin
  prev := nil;
  next := nil;
  key  := 0;
end;
destructor Telem.destroy;
begin
  next.Free;
  prev.Free;
end;
var
  x:Telem; i:integer; H:Pointer;
procedure inicjuj(_wart:integer);
var v:Telem;
begin
   v := Telem.create;
   v.key:= _wart;
   H := v;
end;
procedure dodaj(_wart:integer);
var c:Telem;
begin
  c := Telem.create;
  c.key := _wart;
  c.next := H;
  H := c;
end;
begin
  inicjuj(2);
  dodaj(9);
  dodaj(3);
  dodaj(6);
  dodaj(5);
  x := H;
  i:=1;
  while x.key <> 2 do
  begin
     x := x.next; inc(i);
  end;
  writeln('elem kolejki = 2 to ',i);
  readln;
end.

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