Const (programare)

Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de versiunea revizuită pe 7 februarie 2019; verificările necesită 10 modificări .

În limbajele de programare C , C++ , C# și D , const este un calificator de tip: cuvântul cheie [a] este aplicat tipului de date , indicând faptul că datele sunt const (imuabile). Aceasta poate fi folosită atunci când se declară (declară) constante . O caracteristică distinctivă a constlimbajelor de programare asemănătoare C este atunci când este combinată cu tipuri de date , ceea ce dă un comportament complex atunci când este combinat cu pointeri, referințe, tipuri de date compuse și în verificarea tipurilor.

Introducere

Când se declară [b] obiecte folosind const , valorile lor sunt constante (imuabile), spre deosebire de variabile . Acest caz de utilizare de bază - declararea constantelor - are paralele în multe limbi.

Cu toate acestea, spre deosebire de alte limbi din familia de limbi, C constface parte din tip , nu din obiect . De exemplu, în C const int x = 1;, declară un obiect xde tip const int, unde constface parte din tip. Acesta poate fi citit „(const int) x” - în timp ce în Ada X : constant INTEGER := 1_ se declară o constantă (un fel de obiect) Xde tip INTEGER, adică constantface parte din obiect , nu din tip .

Există două puncte subtile. În primul rând, constpoate face parte din tipuri mai complexe. De exemplu, int const * const x;(expresia este citită din variabila x în direcția opusă) declară un pointer constant la un număr întreg constant, în timp ce int const * x;declară o variabilă indicator la un număr întreg constant și int * const x;declară un pointer constant la un număr întreg variabil. În al doilea rând, deoarece constface parte din tip, este folosit în verificarea tipului. De exemplu, următorul cod este incorect:

void f ( int & x ); //... const int i ; f ( i );

deoarece argumentul transmis la ftrebuie să fie o variabilă de referință la întreg și trebuie să fie i un număr întreg constant . Cerința pentru o astfel de conformitate este o formă de corectitudine a programului, cunoscută și sub numele deconst -corectitudine .  Acest lucru permite proiectarea contractului , în care funcțiile au ca parte a semnăturii de tip dacă își vor schimba argumentele sau nu și dacă valorile lor returnate sunt modificabile (non-constante). Această verificare a tipului este de interes în primul rând pentru pointeri și referințe (adică, atunci când parametrii sunt transmiși prin referință) - mai degrabă decât pentru tipurile de bază, cum ar fi numerele întregi - și pentru tipurile de date compuse sau tipurile șablon, cum ar fi containerele . Poate fi omis din cauza conversiei implicite de tip în timpul execuției programului .constconst

Consecințele

Când este stocată în memoria computerului , constanța nu impune restricții de scriere asupra valorii . consteste mai mult un construct în timp de compilare pe care programatorul îl poate folosi, dar nu este obligat să o facă. Este demn de remarcat faptul că, în cazul literalelor de șir predefinite (cum ar fi const char *), o valoare constantă în C (și C++ ) este de obicei nerescriere, deoarece poate fi stocată într -un segment de memorie care nu poate fi scris .

Alte utilizări

În plus, cum constpoate fi declarată o funcție membru (nestatică). În acest caz, indicatorul thisdin interiorul unei astfel de funcție va avea un tip object_type const * constîn loc de object_type * const. Aceasta înseamnă că funcțiile care sunt neconstante în raport cu acest obiect nu pot fi apelate dintr-o astfel de funcție și nici câmpurile de clasă nu pot fi modificate . În C++, un câmp de clasă poate fi declarat ca mutable(mutable), ceea ce înseamnă că această restricție nu i se aplică. Acest lucru poate fi util în unele cazuri, cum ar fi stocarea în cache , numărarea referințelor și sincronizarea datelor. În aceste cazuri, semnificația (starea) logică a obiectului este imuabilă, dar obiectul este fizic non-constant, deoarece reprezentarea sa pe biți se poate modifica.

Sintaxă

În C, C++ și D, toate tipurile de date, inclusiv cele care sunt definite de utilizator, pot fi declarate const, iar „ const-well-formedness” implică faptul că toate variabilele sau obiectele trebuie declarate ca atare, cu excepția cazului în care trebuie modificate. Această utilizare prudentă constface ca valorile variabile să fie „ușor de înțeles, de urmărit și de gândit” [1] , crescând astfel lizibilitatea și înțelegerea și ușurând munca în echipă și întreținerea codului, deoarece oferă informații despre utilizarea corectă a valorilor acestora. Acest lucru poate ajuta compilatorul , precum și dezvoltatorul atunci când se gândesc la cod. De asemenea, poate permite compilatorului de optimizare să genereze cod mai eficient [2] .

Tipuri de date simple

Pentru tipurile de date simple (non-pointere), utilizarea calificatorului consteste evidentă. Poate fi specificat pe ambele părți ale tipului din motive istorice ( const char foo = 'a';echivalent char const foo = 'a';). În unele implementări, utilizarea constunui tip pe ambele părți (de exemplu, const char const) generează un avertisment, dar nu o eroare.

Indicatori și link-uri

Pentru pointeri și referințe, efectul net consteste mai complicat: atât pointerul în sine, cât și valoarea către care indică, sau ambele, pot fi declarate ca const. Mai mult, sintaxa poate fi, de asemenea, confuză.

Un pointer poate fi declarat un const-pointer către o valoare care poate fi scrisă ( ) , type * const x;sau un pointer care poate fi scris către -valoare ( ) sau un - pointer către - valoare ( ). Un -pointer nu poate fi reatribuit o referință unui alt obiect de la cel original, dar acesta (pointerul) poate fi folosit pentru a schimba valoarea către care indică (o astfel de valoare se numește valoare pointer ) . Astfel, sintaxa pentru variabilele de referință este o sintaxă alternativă pentru -pointers. Pe de altă parte, unui pointer -obiect i se poate reatribui o referință pentru a indica o altă locație din memorie (care trebuie să conțină un obiect de același tip sau tip castable), dar nu poate fi folosit pentru a modifica valorile din memorie pe care le indică la. De asemenea, poate fi definit un -pointer către -obiect , care nu poate fi folosit pentru a modifica valoarea acestuia și căruia nu i se poate reatribui o referință unui alt obiect. consttype const * x; //или: const type * x;constconsttype const * const x;const constconstconstconst

Aceste subtilități sunt ilustrate de următorul cod:

void Foo ( int * ptr , int const * ptrToConst , int * const constPtr , int const * const constPtrToConst ) { * ptr = 0 ; //Ordine: modifică datele prin indicator. ptr = NULL ; //Ordine: schimbă indicatorul. * ptrToConst = 0 ; //Eroare! Nu puteți modifica datele prin indicator. ptrToConst = NULL ; //Ordine: schimbă indicatorul. * constPtr = 0 ; //Ordine: modifică datele prin indicator. constPtr = NULL ; //Eroare! Nu puteți schimba indicatorul. * constPtrToConst = 0 ; //Eroare! Nu puteți modifica datele prin indicator. constPtrToConst = NULL ; //Eroare! Nu puteți schimba indicatorul. } Convenții de notație C

În conformitate cu convențiile normale ale limbajului C pentru declarații, declarațiile sunt listate după utilizarea intenționată, iar asteriscul de lângă indicator este plasat adiacent acestuia, indicând o dereferință. De exemplu, într-o declarație, int *ptrforma dereferențiată *ptreste un număr întreg ( int), iar forma referită ptr este un pointer către un număr întreg. Astfel, constmodifică numele variabilei în dreapta lui însuși .

Convenția în C++ este, dimpotrivă, să se asocieze *cu tipul (adică int* ptr) și citire, ceea ce constmodifică tipul din stânga sa . Prin urmare, int const * ptrToConstpoate fi citit fie ca „ *ptrToConst- this int const” (valoarea indicatorului este imuabilă), fie ca „ ptrToConst- this int const *” (pointer la o valoare întreagă imuabilă).

În acest fel:

int * ptr ; //"*ptr" este o valoare întreagă. int const * ptrToConst ; //"*ptrToConst" -- constantă ("int" -- întreg). int * const constPtr ; //"constPtr" este o constantă ("int *" este un pointer către un întreg). int const * const constPtrToConst ; //"constPtrToConst" este o constantă (pointer), //la fel ca "*constPtrToConst" (valoare).

Note

  1. În D se folosește termenul constructor de tip în loc de calificativ de tip, prin analogie cu constructorii din programarea orientată pe obiecte .
  2. În mod formal, când constface parte din tipul derivat cel mai exterior într-o declarație; indicatorii complică discuția.
  1. Herb Sutter și Andrei Alexandrescu (2005).
  2. De ce argumentul kfree() este constant? (link indisponibil) . lkml.org (12 ianuarie 2013). Data accesului: 9 ianuarie 2016. Arhivat din original pe 4 martie 2016.