Salvarea spatiului
Cind programam aplicatii netriviale, invariabil vine vremea cind dorim mai mult spatiu de memorie decit este disponibil sau ne putem permite. Exista doua moduri de a obtine mai mult spatiu in afara de cel care este disponibil:
[1] Sa se puna mai mult de un obiect mic intr-un octet;
[2] Sa se utilizeze acelasi spatiu pentru a pastra diferite obie 858t1924i cte in momente diferite.
Prima metoda poate fi realizata folosind cimpurile, iar cea de a doua folosind reuniunile. Aceste constructii se descriu in sectiunile urmatoare. Deoarece utilizarea lor tipica este pentru a optimiza pur si simplu un program si deoarece ele sint adesea cele mai neportabile parti ale programului, programatorul trebuie sa gindeasca de doua ori inainte de a le utiliza. Adesea o conceptie mai buna este sa schimbe modul in care se gestioneaza datele; de exemplu, sa se insiste mai mult asupra memoriei alocate dinamic (&3.2.6) si mai putin asupra memoriei prealocate static.
2.5.1. Cimpuri
Se pare extravagant ca sa se utilizeze un caracter pentru a reprezenta o variabila binara, de exemplu un comutator on/off, dar tipul char este cel mai mic obiect care poate fi alocat independent in C++. Este posibil, totusi, sa se inmanuncheze impreuna diferite astfel de variabile foarte mici ca si cimpuri intr-o structura. Un membru se defineste a fi un cimp specificind numarul de biti pe care ii ocupa, dupa numele lui. Se admit si cimpuri nedenumite; ele nu afecteaza sensul cimpurilor denumite, dar pot fi utilizate pentru a face o aranjare mai buna insa dependenta de masina:
struct sreg;
Aceasta se intimpla sa fie aranjarea bitilor la registru de stare 0 la DEC PDP11/45. Un cimp trebuie sa fie de tip intreg si se utilizeaza ca alti intregi exceptind faptul ca nu este posibil sa se ia adresa unui cimp. In modulul kernel al unui sistem de operare sau in debugger, tipul sreg ar putea fi utilizat astfel:
sreg* sr0 = (sreg*)0777572;
//........
if(sr0->access) //access violation
Cu toate acestea, utilizind cimpuri pentru a putea impacheta diferite variabile intr-un singur octet nu neaparat se salveaza spatiu. Se salveaza spatiu la date, dar dimensiunea codului rezultat din manipularea acestor variabile se mareste pe majoritatea masinilor. Programele se stie ca se scurteaza semnificativ cind variabilele binare se convertesc de la cimpuri binare la caractere! Mai mult decit atit, de obicei este mai rapid sa se faca acces la char sau int decit pentru a face acces la un cimp.
2.5.2. Reuniuni
Sa consideram o tabela de simboluri in care o intrare pastreaza un nume si o valoare, iar valoarea este sau un sir sau un intreg:
struct entry;
void print_entry(entry* p)
}
Deoarece string_value si int_value nu pot fi utilizate in acelasi timp, evident se pierde spatiu. Se poate recupera usor specificind ca ambii ar trebui sa fie membri ai unei reuniuni, ca mai jos:
struct entry;
};
Aceasta lasa tot codul care foloseste pe entry neschimbat, dar asigura faptul ca atunci cind entry se aloca, string_value si int_value sa aiba aceeasi adresa. Aceasta implica, ca toti membri unei reuniuni sa aiba in comun acelasi spatiu care permite pastrarea celui mai mare membru.
Utilizind reuniunea in asa fel ca totdeauna sa folosim membrul care a fost pastrat in ea, se obtine o optimizare pura. Cu toate acestea, in programe mari, nu este usor sa se asigure ca o reuniune se utilizeaza numai in acest mod si se pot introduce erori subtile. Este posibil sa se incapsuleze o reuniune in asa fel incit corespondenta intre tipul cimp si tipurile membrilor unei reuniuni sa fie garantat ca este corecta (&5.4.6).
Reuniunile sint uneori utilizate pentru "conversie de tip" (aceasta se face in principiu prin programe introdu-se in limbaj in afara facilitatilor de conversie a tipului, unde este necesar sa fie facuta). De exemplu, pe VAX acestea convertesc un int in int* pur si simplu prin echivalenta de biti.
struct fudge;
};
fudge a;
a.i = 4096;
int* p = a.p; //bad usage
Cu toate acestea, aceasta nu este o conversie reala; pe anumite masini un int si un int* nu ocupa acelasi spatiu, iar pe altele nici un intreg nu poate avea o adresa impara. O astfel de utilizare a unei reuniuni nu este portabila si exista un mod explicit si portabil de a specifica aceasta conversie (&3.2.5).
Reuniunile sint ocazional utilizate in mod deliberat pentru a elimina conversia de tip. Am putea, de exemplu, utiliza un fudge pentru a gasi reprezentarea pointerului 0:
fudge.p = 0;
int i = fudge.i; // i nu este necesar sa fie 0
Este de asemenea posibil sa se dea un nume unei reuniuni; adica ea formeaza un tip in adevaratul sens al lui. De exemplu, fudge ar putea fi declarata astfel:
union fudge;
si folosita exact ca inainte. Reuniunile numite au de asemenea, utilizari proprii (vezi &5.4.6).
|