Referenca (programiranje)

Referenca je vrsta promjenljive u programiranju.

Reference su najsrodnije pokazivačima. Koriste se u velikom broju programskih jezika, kao što su C++, Java, PHP, Javaskript i drugi.

Uloga reference je da čuva adresu neke druge promjenljive i sve operacije koje se čine na njima, prosljeđuju promjenljivama na koje same pokazuju. Sintaksa referenci, u svim programskim jezicima koji ih podržavaju, je takva da dozvoljava samo rad sa memorijskom lokacijom na koju referenca ukazuje - nije dozvoljen rad sa memorijskom lokacijom koja predstavlja referencu. To možemo uporediti sa pokazivačima, koji podržavaju sve aritmetičke operacije i operacije dodjele nad samim pokazivačem, kao i nad vrijednošću na koju pokazivač pokazuje.

U različitim programskim jezicima, reference se koriste drugačije. U nekim programskim jezicima sve promjenljive su u stvari reference, i ne predstavljaju same po sebi vrstu promjenljive, nego ukazuju na karakterističan način prenosa argumenata funkcije (npr. Java, Javaskript), dok se u drugim jezicima tretiraju baš kao posebna podvrsta podataka, poput pokazivača i moraju se eksplicitno zahtijevati posebnom sintaksom (npr. C++, PHP).

U programskom jeziku C++, reference su uvedene radi pojednostavljenog pisanja; naslijedivši kompletnu sintaksu iz C-a, a samim time i pokazivače, arhitekte C++-a su odlučile uvesti reference koje bi u određenim aspektima preuzele ulogu pokazivača ali bile i znatno jednostavnije za upotrebu.

Bitno je naglasiti da pokazivači i reference nisu ekvivalentni u C++-u i da, štaviše, postoje značajne razlike:

    • pokazivači mogu primiti vrijednost u bilo kom trenutku za vrijeme rada programa
    • reference moraju biti inicijalizovani pri konstruisanju, i ne mogu mijenjati vrijednost
    • pokazivači mogu sadržati vrijednost NULL, tj. ne pokazivati ni na šta
    • reference moraju biti inicijalizovane na neku vrijednost, ili će kompajler prijaviti grešku
    • pokazivači se mogu koristiti za implementaciju nizova, matrica, dinamičku alokaciju memorije i prosljeđivanje argumenata funkcije „po referenci“
    • reference se mogu koristiti samo za prosljeđivanje argumenata funkcije po referenci
    • pokazivači koriste operator * (zvjezdicu) za dereferenciranje i operator & (ampersand) za referenciranje
    • reference ne koriste nijedan od navedenih operatora, što ih čini znatno jednostavnijim za rad
    • mogu postojati pokazivači na pokazivače
    • ne mogu postojati pokazivači na reference

Deklaracija

uredi

Deklaracija referenci u programskom jeziku C++ se vrši na sljedeći način:

тип_циљне_промјенљиве & име_референце = име_циљне_промјенљиве;

Iz date definicije vidimo da se znak '&' koristi za označavanje da je име_референце referenca, i primjećujemo da je dodjela ciljne promjenljive referenci neophodna već za vrijeme same deklaracije reference; pri navođenju ciljne promjenljive nije neophodno koristiti nikakve posebne znake (uporedite to sa dodjelom pokazivaču, u obliku: име_показивача = &име_циљне_промјенљиве, gdje je potrebno navesti adresni operator (&) da bi pokazivač primio odgovarajuću vrijednost).

Jednom ovako deklarisana promjenljiva se ne može izmijeniti - svaka dodjela u obliku:

име_референце = нека_друга_промјенљива;

će biti ekvivalentna dodjeli:

име_циљне_промјенљиве = нека_друга_промјенљива;

Prosljeđivanje argumenata

uredi

Poglavlje „deklaracija“ je pokazalo školski primjer deklaracije reference, koji se u praksi skoro nikad ne koristi. Najčešća upotreba referenci je pri prosljeđivanju argumenata funkciji, kada se pomoću referenci želi reći „argumentima koji se proslijede na ovom mjestu, funkcija će moći prilaziti direktno i mijenjati njihovu vrijednost“. Drugim riječima, referenca će tada preuzeti ulogu pokazivača, i dozvoliti pristup originalnoj promjenljivoj koja je proslijeđena u trenutku poziva funkcije.

Pogledajmo nekoliko primjera - nefunkcionalan primjer, zatim funkcionalan primjer realizovan sa pokazivačima i na kraju funkcionalan primjer realizovan pomoću referenci.

Nefunkcionalan primjer:

# include <iostream>
using namespace std;

void povecajZa1(int x )
{
    x = x + 1; // очекујемо да се прослијеђени аргумент
               // измијени након завршетка функције
               // оно што се у ствари деси је да се прослиједи
               // само '''копија''' прослијеђеног аргумента,
               // и оригинална промјенљива остаје нетакнута
}

int main()
{
    int x = 3;
    povezajZa1(x );
    cout << x << endl; // штампа се 3!
}

Funkcionalan primjer realizovan pomoću pokazivača:

# include <iostream>
using namespace std;

void povecajZa1(int * x ) // функцији ће бити прослијеђена '''адреса'''
                           // неког цијелог броја, а x ће бити показивач
                           // на локацију са том адресом
{
    *x = *x + 1; // сада се повећава оно на шта показивач x показује
                 // (а то је промјенљива чија адреса нам је послата)
}

int main()
{
    int x = 3;
    povezajZa1(&x ); // шаљемо адресу промјенљиве x
    cout << x << endl; // штампа се 4!
}

Funkcionalan primjer realizovan pomoću referenci:

# include <iostream>
using namespace std;

void povecajZa1(int & x ) // проглашавамо x '''референцом'''
                           // на прослијеђени аргумент
{
    x = x+1; // сада се повећава оно на шта референца x показује
             // (а то је '''оригинални''' прослијеђени аргумент)
}

int main()
{
    int x = 3;
    povezajZa1(x );
    cout << x << endl; // штампа се 4!
}

Lako je primijetiti da je razlika između nefunkcionalnog primjera i primjera sa referencama mnogo manja od razlike između nefunkcionalnog primjera i primjera sa pokazivačima. Pokazivači zahtijevaju dereferenciranje pomoću operatora zvjezdice, referenciranje pomoću adresnog operatora, i deklaraciju funkcije koja ukazuje na upotrebu pokazivača, dok reference zahtijevaju samo to - ampersand u deklaraciji funkcije - i funkcija ostaje identična, kao i njen poziv.

PHP ima složenu upotrebu referenci, čija sintaksa zavisi od vrste primjene. Postoji nekoliko primjena referenci:

  • vraćanje reference na određenu promjenljivu kao izlazne vrijednosti funkcije
  • dodjela jedne promjenljive drugoj, čime druga postaje referenca na prvu, bez stvarnog kopiranja vrijednosti
  • prosljeđivanje argumenta funkcije „po referenci“ (kao u jeziku C++
  • upotreba u petlji foreach

Vraćanje reference

uredi

Vraćanje reference kao izlazne vrijednosti funkcije se čini tako što stavimo ampersand iza ključne riječi function pri deklaraciji funkcije:

function & vratiLokalnuVrijednost()
{
    $niz = Array("prvi" => 10, "drugi" => 20 );
    return $niz;
}

Na taj način funkcija alocira lokalnu promjenljivu, ali da bi pri vraćanju rezultata izbjegla nepotrebno kopiranje vrijednosti, vraća referencu na lokalnu promjenljivu $niz.

Referentna dodjela

uredi

Referenciranje jedne promjenljive ka drugoj se takođe postiže pomoću operatora ampersanda, ali na sledeći način:

$b = 2;
$a = &$b;

Tada $a postaje doslovno isto što i $b, sinonim, lažno ime, odnosno baš referenca na $b. Svaka promjena $a utiče i na $b i obrnuto.

Argumenti funkcije

uredi

Prosljeđivanje argumenta funkciji se vrši na isti način kao i u C++-u, dakle stavljajući ampersand ispred imena argumenta funkcije:

function povecajZa1(& $x )
{
    $x = $x+1;
}

foreach

uredi

Pri korištenju foreach petlje, u svakom krugu se odgovarajući element niza kopira u privremenu memorijsku lokaciju. Ukoliko koristimo reference, ovaj proces se znatno ubrzava jer se radi sa referencama na odgovarajuće elemente niza, a ne sa njihovim kopijama. Reference se u ovoj situaciji koriste tako što se stavi ampersand ispred imena promjenljive koja predstavlja ime svakog pojedinačnog elementa niza u odgovarajućem krugu:

foreach ($niz as &$element ) {
    $element += 1; // ова промјена ће утицати на стварне елементе низа
}

foreach ($niz as $element ) {
    $element += 1; // ова промјена '''неће''' утицати на стварне елементе низа
}

Java i Javaskript

uredi

U programskim jezicima Java i Javaskript, sve promjenljive su u stvari reference koje ukazuju na memoriju alociranu, posredno ili neposredno, pomoću ključne riječi new, sa izuzetkom promjenljivih koje sadrže vrijednosti nekog od elementarnih tipova (cjelobrojne promjenljive, znakovne vrijednosti, realni brojevi itd.). Izuzetka, međutim, nema kad se govori o prenošenju argumenata funkciji; u tom slučaju sve, pa i promjenljive nekog od elementarnih tipova, se prenose kao reference. Ovo predstavlja znatno ubrzanje rada programa napisanih u nekom od ovih programskih jezika. Pisanje samih programa nije postalo ništa složenije, budući da takve „referentne“ promjenljive ne zahtijevaju nikakvu posebnu sintaksu i koriste se kao obične statičke promjenljive.

Vidi još

uredi