Приказивање постова са ознаком const correctness. Прикажи све постове
Приказивање постова са ознаком const correctness. Прикажи све постове

среда, 8. април 2009.

конст коректност 2


Интересантност о којој до данас нисам мислио. Колега ми је отворио очи. Наиме, ради се овоме: колега је послао фајл са Ц кодом на преглед. Његов код је имао функције које су изгледале отприлико овако:


/* Primer const argumenta u definiciji. */
static int foo(const int bar)
{
if (bar > 7)
global_bar = bar - 7;
}


На то сам ја коментарисао да обично не "губим" време декларишући формални аргумент конст, на шта ми је одговорио (потпуно исправно) да је у дефиницији конст врло корисна, за разлику од декларације.

Конст формални аргумент у декларацији сам коментарисао, али ја лично никада нисам размишљао о томе да дефиниција може да дода модификатор конст формалном аргументу, а да тиме не дефинише неку нову функцију.

На пример, нека је у заглављу оваква декларација:


/* Deklaracija funkcije. */
int funkcija(const char *);


А имплементација може овако:


/* Definicija funkcije. */
int funkcija(const char * const ime)
{
// ...
}


Заиста, овако се кориснику функције (који обично гледа прототип декларисан у заглављу) не намеће имплементациони детаљ за њега (корисника) небитан, док се читаоцу имплементације одмах даје до знања да се вредност формалног аргумента "ime" неће мењати у телу функције. Дакле, даје читаоцу сличну информацију као и конст модификатор на локалној варијабли.

Даље је интересантно приметити да додавање конст модификатора формалном аргументу у декларацији у суштини не мења декларацију. На пример, ове две декларације декларишу исту функцију.



/* Ekvivalentne deklaracije funkcije. */
int funkcija(const char *);
int funkcija(const char *const);



Oва друга је очигледно рогобатнија и представља једну од оних декларација у којима сам причао и у претходном чланку.

недеља, 22. март 2009.

конст коректност

Kључна реч "const" у језицима це и це плус плус.

У пројектима често срећем код у којима се ова кључна реч не користи или се не користи доследно. То је штета јер доприноси не само читљивости него и преношењу идеје о томе шта се дешава у одговарајућој функцији ономе који је чита, док компајлер обезбеђује да коректност буде примењена.

Уместо много речи, ево неколико примера. Рецимо да имамо функцију која треба да као аргумент прими показивач на низ карактера. За пример приказујем три функције од којих свака као аргумент има показивач на низ карактера:

/* Deklaracije. */
int f1(char *tekst);
int f2(const char *tekst);
int f3(char const *tekst);
int f4(const char *const tekst);
int f5(char *const tekst);

У чему је разлика између ових декларација? Наравно, у коришћењу речи конст.

Прва нам каже да ће низ на који показује формални параметар "tekst" можда бити мењан у функцији; друга функција нам каже да низ на који показује текст сигурно неће бити мењан унутар функције (али не говори ништа о томе да ли ће вредност аргумента "tekst" бити мењана, што са тачке гледишта корисника функције није ни битно).

Трећа функција има идентично значенје као и функција "f2". Неко више воли такав запис, неко као у другој функији - све једно је. 

Четврта функција поред тога што "обећава" да неће мењати низ на који показује формални аргумент, још казује да неће мењати ни вредност тог аргумента. Са тачке гледишта корисника функције, ово додатно конст је ирелевантно - позивној функцији је свеједно шта ће се са аргументом десити. Иако није неправилна, ова декларација можда мало непотребно оптерећује декларацију и ја је обично не користим. 

Пета функција је дата само ради комплетности, ни овакву декларацију функције не користим јер, као што сам раније рекао, говори о нечему што онога ко користи функцију не занима. Семантички, идентична је функцији "f1", дакле низ на који показује аргумент може да буде мењан унутар функције.

Слично је са декларацијама променљивих, само што овде често има смисла користити и варијанте "char *const tekst;" и "const char * const tekst" у зависности од контекста.

У це-плус-плусу постоји и коршћење речи конст у својству модификатора метода класе. Ево примера:

/* Jednostavan primer const kao
modifikatora metoda. */
#include <string>
#include <iostream>

using std::string;
using std::cout;
using std::endl;

class Zaposleni
{
public:
Zaposleni(const string &ime)
: _ime(ime) {}

virtual ~Zaposleni() {}

string ime()
{
cout << "Pozvana ne-konst metoda." << endl;
return _ime;
}

string ime() const
{
cout << "Pozvana konst metoda." << endl;
return _ime;
}

private:
string _ime;
};

void stampajZaposleni(const Zaposleni &zap)
{
cout << "U funkciji stampajZaposleni" << endl;
cout << zap.ime() << endl;
}

int main(int argc, char* argv[])
{
Zaposleni zap("Mika");
cout << "Poziv preko konst deklarisane promenljive." << endl;
stampajZaposleni(zap);
cout << "Sada poziv preko ne-konst deklarisane promenljive: " << endl;
cout << zap.ime() << endl;
return 0;
}

Пример је тривијалан, али има једну интересантну тачку: који од два метода за име ће бити позван у функцији stampajZaposleni? Наравно, биће позване методе које су означене са конст јер смо и формални аргумент "zap" у функцији stampajZaposleni означили са конст у декларацији функције. Уколико искоментаришемо конст декларације метода "ime", откирћемо да програм више не може да се искомпајлира јер не-конст метода "ime" не "обећава" да неће мењати унутрашње стање објекта.

За разлику од тога, у самој функцији "main" ће бити позвана не-конст метода јер је таква и декларација локалне променљиве "zap".



Закључак: конст коректност није претерано компликована за разумевање. Па ипак, уколико се добро не разуме и не користи правилно, брзо доводи до пројеката чија се конст коректност више не може поправити. Зато је важно од самог почетка пројекта правилно користити ову интересанту и веома корисну особину програмског језика.