Mutatók

Tartalom:

Az ADAban egy mutató mutathat

Mutató tipust az alábbi formában definiálhatunk:

  1. TYPE NÉV IS ACCESS TIPUS;
  2. TYPE NÉV IS ACCESS ALL TIPUS;
  3. TYPE NÉV IS ACCESS CONSTANT INTEGER;
Magyarázat:
  1. Csak dinamikusan lefoglalt objektumra mutathat.
  2. Dinamikusan- vagy a deklarációs részben lefoglalt objektumra mutathat.
  3. Konstans objektumra is mutathat, de a mutatott értéket nem tudjuk rajta keresztül megváltoztatni. (Mutathat nem konstansra is, de a mutatott objektumot akkor sem tudjuk a mutatón keresztül megváltoztatni)

A mutatók használata egy példán keresztül:

PROCEDURE MAIN IS  
    TYPE PINT IS ACCESS ALL INTEGER; --Létrehozunk egy integerre mutató tipust
    P,Q,R : PINT; --Deklarálunk három PINT tipusú változót
    I : ALIASED INTEGER --Az ALIASED kulcsszóval tudjuk megengedni, hogy a statikus változóra mutató mutasson.
--(Ez a dinamikusan lefoglalt változóra nem vonatkozik)
BEGIN
    I := 42;
    P := I'ACESS; --A P mutatót ráállítjuk az I változóra. Azaz a P mutatónak értékül adjuk az I címét.
    P.ALL := 137; --A I változó értékét megváltoztatjuk a P mutatón keresztól. Azaz a P által mutatott memóriaterület értékét megváltoztatjuk
    Q := NEW INTEGER; --Dinamikusan lefoglalunk egy INTEGERnyi memóriaterületet, és a címét átadjuk Q-nak
    R := NEW INTEGER'(42); --Dinamikusan lefoglalunk egy INTEGERnyi memóriaterületet, adunk neki kezdőértéket, majd a címét átadjuk Q-nak
END MAIN;

Újabb példa a mutatók használatára:

TYPE PKONST_INT IS ACCESS CONSTANT INTEGER;
TYPE PINT IS ACCESS ALL INTEGER;
P : PKONST_INT;
Q : PINT;
I : ALIASED INTEGER;
K : ALIASED CONSTANT INTEGER; --Olyan konstans amire lehet mutatót állítani
KP : CONSTANT PKONTS_INT := K'ACCESS; --Kell adni kezdőértéket, mert KP konstans
KQ : CONSTANT PINT := I'ACCESS; --Kell adni kezdőértéket, mert KQ konstans
helyes műveletek:
P := K'ACCESS; --Mert P egy konstans integerre mutató mutató, a K meg egy konstans integer
P := I'ACCESS; --Egy konstans integerre mutató mutató mutathat nem konstans integerre is, csak a mutatón keresztül nem tudjuk megváltoztatni az I értékét.
Q := I'ACCESS;
Q.ALL := 29;
P := NEW INTEGER'(2);
KQ.ALL := 1; --Mert csak KQ konstans, az általa mutatott terület nem az.
Hibás műveletek:
P.ALL := 5; --Mert a P konstans integerre mutató, így P-n keresztül nem lehet megváltoztatni a memória értékét
Q := K'ACCESS; --Mert Q nem mutathat konstans integerre
P := NEW INTEGER; --Mert P konstans mutató, és lefoglaláskor nem adtunk kezdőértéket. Később már nem is adhatnánk.
KP := NEW INTEGER'(100); --Mert KP konstans, nem változtathatjuk meg az értékét
KQ := NEW INTEGER'(100); --Mert KP konstans, nem változtathatjuk meg az értékét
KP.ALL := 10; --Mert KP konstansra mutat.

Tömbre ill. rekordra mutató mutatók:

Tekintsük az alábbi tipusdefiniciókat:
 
TYPE VEKT IS ARRAY(INTEGER RANGE <>) OF POSITIVE;
 
TYPE REC IS RECORD
    X : INTEGER;
    Y : CHARACTER;
END RECORD;
 
TYPE PVEKT IS ACCESS ALL VEKT;
TYPE PREC IS ACCESS ALL REC;
 
 
Ekkor PVEKT egy VEKT tipusú tömbre mutathat, a PREC pedig egy REC tipusú rekordra
 
PVEKTen keresztül a tömb i-edik elemét a következő módon tudjuk módosítani:
 
PVEKT.ALL(i) := 42;
PVEKT(i) := 42;
 
A két módszer ekvivalens, tehát tömbre mutató mutató esetén az ALL kulcsszó elhagyható.
 
 
Ugyanaz a helyzet rekordnál is:
 
PREC.ALL.X := 42;
PREC.X := 42;
 
A két sor ekvivalens egymással.

Tekintsük a következő példát:

TYPE TOMB IS ARRAY(1..10) OF INTEGER;  
TYPE ALITOMB IS ARRAY(1..10) OF ALIASED INTEGER;  
TYPE PINT IS ACCESS ALL INTEGER;  
TYPE PTOMB IS ACCESS ALL TOMB;  
TYPE PALITOMB IS ACCESS ALL ALITOMB  
X : ALIASED TOMB;  
Y : ALITOMB;  
Z : ALIASED ALITOMB;  
PI : PINT;  
P : PTOMB;  
PA : PALITOMB;  
A következő értékadások helyesek:
P := X'ACCESS; --Az X tömb címét értékül adjuk P-nek. Azaz P-t ráállítjuk X-re.
PI := Y(1)'ACCESS; --Jó, mert a PI INTEGERre mutató mutató, a Y tömb elemei pedig ALIASED INTEGEREK
P := Z'ACCESS;
PI := Z(1)'ACCESS;
A következő értékadások helytelenek:
I := X(1)'ACCESS; --Mert az X tömb elemei nem ALIASED INTEGERek, ezért nem lehet rájuk állítani mutatót
P := Y'ACCESS; --Mert az Y nem ALIASED

Az élettartam:

Egy dinamikusan lefoglalt memóriaterület addig érhető el, amíg az őt tartalmazó blokk aktív. Ezután már nem érhető el, de még a memóriában marad. Eltávolításáról az ADA „szemétgyűjtő” algoritmusa gondoskodik, tehát nem kell a dinamikusan lefoglalt memóriaterület felszabadításával foglalkoznunk. Nemcsak nem kell, hanem nem is ajánlott. Ennek előnye, hogy nem fordulhat elő az, hogy megfeledkezünk a felszabadításról és szépen lassan lefoglaljuk az egész memóriaterületet. Hátránya, hogy nem tudjuk, kontrollálni a felszabadítást. A memória nem közvetlenül akkor szabadul fel, amikor már nincs szükség arra a területre, hanem amikor a szemétgyűjtő algoritmus lefut és felszabadítja. (Lehet, hogy pont akkor fut le a szemétgyűjtő algoritmus, amikor olyan feladatot hajt végre a programunk aminek nagy processzorteljesítményre van szüksége és ez fölöslegesen lassítja.)  
Esetenként azonban mégis szükség lehet arra, hogy mi szabadítsuk fel a memóriát. Ilyen esetben használjuk az ADA.UNCHECKED_DEALLOCATION sablon eljárást.

példa az ADA.UNCHECKED_DEALLOCATION sablon használatára:

WITH ADA.UNCECKED_DEALLOCATION
PROGRAM MAIN IS
    TYPE TOMB IS ARRAY(INTEGER RANGE <>) OF INTEGER; --Létrehozunk egy tömb tipust
    TYPE PTOMB IS ACCESS TOMB; --Definiálunk egy TOMB-re mutató mutató tipust
    PROCEDURE FREE IS NEW ADA.UNCECKED_DEALLOCATION(TOMB,PTOMB); --Példányosítjuk a sablon eljárásunkat. Első paraméter a mutatott objektum tipusa, a második pedig a mutató tipus
P : PTOMB;
BEGIN
    P := new TOMB; --Dinamikusan létrehozunk egy tömböt és ráállítjuk P-t
    FREE(P); --Felszabadítjuk a P által mutatott területet
END MAIN;

Láncolt adatszerkezet:

Mutató definiálásakor szükségünk van a mutatott típusra (most a listaelemre).
A listaelem definiálásakor pedig szükségünk van a mutató tipusra.
Ezt a patthelyzetet a következő módon oldhatjuk fel.
 
TYPE LISTAELEM; --Megmondjuk a fordítónak, hogy majd később definiáljuk, de tudja, hogy van ilyen
TYPE PLISTAELEM IS ACCESS LISTAELEM; --Mostmár tudjuk definiálni a PLISTAELEMET, mert a fordito tudja, hogy legy egy LISTAELEM tipus
TYPE LISTAELEM IS RECORD --Definiálhatjuk a LISTAELEMet is
    ERTEK : INTEGER;
    KOVETKEZO : PLISTAELEM;
END RECORD;

Példaprogramok:

 
 
VISSZA