C++ Const Utilizare Const Explicație (Programare, C++, Constante)

RoR a intrebat.
const int* const Method3(const int* const&) const;

Poate cineva să explice utilizarea fiecăreia dintre const?

Comentarii

12 răspunsuri
satnhak

Citește asta: https://isocpp.org/wiki/faq/const-correctness

Final const înseamnă că funcția Method3 nu modifică membrii nemutabili ai clasei sale.

const int* const înseamnă un pointer constant către un int constant: adică un pointer care nu poate fi modificat, către un int care nu poate fi modificat: singura diferență între aceasta și const int& este că acesta poate fi null

const int* const& înseamnă o referință la un pointer constant la un int constant. De obicei, pointerii nu se transmit prin referință; const int* & are mai mult sens, deoarece ar însemna că pointerul ar putea fi modificat în timpul apelării metodei, ceea ce ar fi singurul motiv pentru care aș putea vedea să se treacă un pointer prin referință, const int* const& este, din toate punctele de vedere, același lucru cu const int* const cu excepția faptului că, probabil, este mai puțin eficient, deoarece pointerii sunt tipuri de date vechi și simple (POD), iar acestea ar trebui, în general, să fie transmise prin valoare.

ildjarn

Este mai ușor de înțeles dacă rescrieți asta ca fiind complet echivalent

// v───v───v───v───v───v───v───v───v───v───v───v─┬┐
//                                               ││
//  v──#1    v─#2             v──#3    v─#4      #5
   int const * const Method3(int const * const&) const;

apoi citiți-o de la dreapta la stânga.

#5 spune că întreaga declarație a funcției din stânga este const, ceea ce implică faptul că aceasta este în mod necesar o funcție membră și nu o funcție liberă.

#4 spune că pointerul din stânga este const (nu poate fi modificat pentru a indica o altă adresă).

#3 spune că int din stânga este const (nu poate fi modificat pentru a avea o valoare diferită).

#2 spune că pointerul din stânga este const.

#1 spune că int la stânga este const.

Punând totul cap la cap, puteți citi acest lucru ca fiind un const funcție membră numită Method3 care primește o referință la un element const la un pointer la un int const (sau un const int, dacă preferați) și returnează un const pointer la un int const (const int).

(N.b. #2 este complet superfluu).

Alexander Gessler

Mai întâi de toate const T este echivalent cu T const.

const int* const este, prin urmare, echivalent cu int const * const.

Atunci când citiți expresii cu o mulțime de const și pointeri în ele, încercați întotdeauna să să le citiți de la dreapta la stânga (după aplicarea transformării de mai sus). Deci, în acest caz, valoarea de returnare este un pointer const către un const int. Realizarea pointerului în sine const nu are sens în acest caz, deoarece valoarea de returnare nu este o lvaloare care să poată fi modificată. Realizarea vârfului constgarantează însă că apelantul nu poate modifica valoarea int (sau matrice de ints) returnat de Method3.

const int*const& devine int const*const&, deci este un referință la un pointer const la un pointer const int. Nici transmiterea unui pointer const prin referințe nu are sens – nu puteți modifica valoarea la care se face referire, deoarece pointerul este const iar referințele și pointerii ocupă aceeași capacitate de stocare, astfel încât nu se face nici o economie de spațiu.

Ultima const indică faptul că metoda nu modifică valoarea this obiectul. Adresa this pointerul din corpul metodei va avea declarația (teoretică) T const * const this. Aceasta înseamnă că o const T* obiect va putea apela T::Method3().

Comentarii

  • Votând acest răspuns (și răspunsul similar al lui ildjarn), în parte pentru că a subliniat faptul că totul are mai mult sens dacă nu se pune primul consts în capul frazei. Tocmai de aceea cred că este o practică proastă să pui const acolo, chiar dacă limba o permite și este cea mai frecventă utilizare. –  > Por T.E.D..
Yony

O modalitate ușoară de a reține regulile de const este să vă gândiți la ele în felul următor: const se aplică la lucrul din stânga sa, cu excepția cazului în care nu există nimic în stânga sa.

Deci, în cazul lui const int * const, prima const nu are nimic în stânga sa, deci se aplică la int iar cea de-a doua are ceva în stânga sa, deci se aplică indicatorului.

Această regulă vă spune, de asemenea, ce s-ar întâmpla în cazul în care aveți const int const *. Deoarece ambele const se aplică la int această expresie este redundantă și, prin urmare, invalidă.

justin
const /* don't modify the int or array of ints' value(s) */
int* const /* as a retval, ignored. useless declaration */
Method3(const /* don't modify the int or array of ints' value(s) */
int* const /* don't modify the pointer's value, the address to which `pointer` points to. e.g. you cannot say `++pointer` */
&) const; /* this method does not modify the instance/object which implements the method */

Jason

Îmi place să folosesc metoda „clock” sau „spiral” în care, pornind de la numele identificatorului (în acest caz Method3), citiți înainte și înapoi de la stânga la dreapta, înapoi la stânga etc., pentru a decoda convențiile de denumire. Astfel, const int* const Method3(const int* const&) const este o metodă de clasă care nu modifică niciun membru al clasei (al unei clase fără nume) și ia o referință constantă la un pointer care indică o constantă int și returnează un pointer constant la o constantă int.

Sper să vă fie de ajutor,

Jason

Albert Chen

O modalitate ușoară de a vă aminti const în C++ este atunci când vedeți un cod în formă de genul:

XXX const;
const YYY;

XXX, YYY va fi o componentă constantă,
XXX const form:

function ( def var ) const;    ------#1
* const;                       ------#2

const YYY form:

const int;                     ------#3
const double;

Oamenii folosesc de obicei aceste tipuri. Când vedeți "const&" undeva, nu vă simțiți confuz, const descrie ceva înainte de el însuși. așa că răspunsul la această problemă este de la sine înțeles acum.

const int* const Method3(const int* const&) const;
  |          |             |          |       |
  #3         #2            #3         #2      #1

MrDetective

Vreau doar să menționez că const int* const& este într-adevăr o referință constantă la const int*. De exemplu:

int i = 0;
int j = 1;
int* p = &i;
int* q = &j;
const int* const& cpref = p;
cpref = q; //Error: assignment of read-only reference 'cpref'

Este și cazul lui int* const&ceea ce înseamnă: „O referință constantă la int*„.
Dar const int*& este o referință neconstantă la const int*.
Sper că vă ajută.

Nick Strupat

Citirea de la dreapta la stânga face mai ușoară înțelegerea modificatorilor.

O metodă const care ia o referință la un pointer const la un int const numit Method3 care returnează un pointer const la un const int.

  1. O metodă const nu poate modifica membrii (cu excepția cazului în care aceștia nu sunt în mod explicitmutable)
  2. Un pointer const nu poate fi modificat pentru a indica altceva.
  3. Un int const (sau orice alt tip) nu poate fi modificat.

Jollymorphic

const #1: Pointerul returnat de Metoda3 se referă la un const int.

const #2: Valoarea pointerului returnat de către funcția în sine este const. Aceasta este o const inutilă (deși valabilă din punct de vedere gramatical), deoarece valoarea returnată de o funcție nu poate fi o valoare l.

const #3: Tipul de pointer transmis prin referință la funcție indică un const int.

const #4: Valoarea pointerului transmisă prin referință la funcție este, la rândul ei, un pointer const. În mod normal, declararea unei valori care este transmisă unei funcții ca fiind const ar fi inutilă, dar această valoare este transmisă prin referință, astfel încât poate fi semnificativă.

const #5: Funcția (probabil o funcție membră) este const, ceea ce înseamnă că nu are voie (a) să atribuie valori noi niciunui membru al obiectului din care face parte sau (b) să apeleze o funcție membră non-const asupra obiectului sau asupra oricăruia dintre membrii acestuia.

Mahesh
  • const la sfârșitul metodei se află calificativul care semnifică faptul că starea obiectului nu va fi modificată.

  • const int*const& înseamnă că primește prin referință un pointer const la o locație const.Acesta nu se poate schimba pentru a indica o locație diferită și nici nu poate schimba valoarea la care indică.

  • const int*const este valoarea de întoarcere care este, de asemenea, un pointer constant către o locație constantă.

Rastus7

Câteva exemple ar fi bune pentru a demonstra acest concept, cu cât mai multe cu atât mai bine imho.

class TestClass
{
private:
   int iValue;
   int* oValuePtr;
   int& oValueRef;

public:
   int TestClass::ByValMethod1(int Value)
   {
      // Value can be modified
      Value++;

      // iValue can be modified
      iValue = Value;
      iValue += 1;

      // Return value can be modified
      return ++iValue;
   }

   int TestClass::ByValMethod2(const int Value)
   {
      // Value *cannot* be modified
      // Variable is const variable
      Value++;

      // iValue can be modified
      iValue = Value;
      iValue += 1;

      // Return value can be modified
      return ++iValue;
   }

   const int TestClass::ByValMethod3(int Value)
   {
      // Value can be modified
      Value++;

      // iValue can be modified
      iValue = Value;
      iValue += 1;

      // Return value can be modified
      return ++iValue;
   }

   const int TestClass::ByValMethod4(const int Value)
   {
      // Value *cannot* be modified
      // Variable is const variable
      Value++;

      // iValue can be modified
      iValue = Value;
      iValue += 1;

      // Return value can be modified
      return ++iValue;
   }

   const int TestClass::ByValMethod5(const int Value) const
   {
      // Value *cannot* be modified
      // Variable is const variable
      Value++;

      // iValue *cannot* be modified
      // Access through a const object
      iValue = Value;
      iValue += 1;

      // Return value *cannot* be modified
      // Access through a const object
      return ++iValue;
   }

   int& TestClass::ByRefMethod1(int& Value)
   {
      // Value can be modified
      Value++;

      // oValueRef can be modified
      oValueRef = Value;
      oValueRef += 1;

      // Return value can be modified
      return ++oValueRef;
   }

   int& TestClass::ByRefMethod2(const int& Value)
   {
      // Value *cannot* be modified
      // Variable is const variable
      Value++;

      // oValueRef can be modified
      oValueRef = Value;
      oValueRef += 1;

      // Return value can be modified
      return ++oValueRef;
   }

   const int& TestClass::ByRefMethod3(int& Value)
   {
      // Value can be modified
      Value++;

      // oValueRef can be modified
      oValueRef = Value;
      oValueRef += 1;

      // Return value can be modified
      return ++oValueRef;
   }

   const int& TestClass::ByRefMethod4(const int& Value)
   {
      // Value *cannot* be modified
      // Variable is const variable
      Value++;

      // oValueRef can be modified
      oValueRef = Value;
      oValueRef += 1;

      // Return value can be modified
      return ++oValueRef;
   }

   const int& TestClass::ByRefMethod5(const int& Value) const
   {
      // Value *cannot* be modified
      // Variable is const variable
      Value++;

      // oValueRef can be modified
      oValueRef = Value;
      oValueRef += 1;

      // Return value can be modified
      return ++oValueRef;
   }

   int* TestClass::PointerMethod1(int* Value)
   {
      // Value can be modified
      Value++;

      // oValuePtr can be assigned
      oValuePtr = Value;

      // oValuePtr can be modified
      oValuePtr += 1;

      // Return value can be modified
      return ++oValuePtr;
   }

   int* TestClass::PointerMethod2(const int* Value)
   {
      // Value can be modified
      Value++;

      // oValuePtr cannot be assigned
      // const int* to int*
      oValuePtr = Value;

      // oValuePtr can be modified
      oValuePtr += 1;

      // Return value can be modified
      return ++oValuePtr;
   }

   const int* TestClass::PointerMethod3(int* Value)
   {
      // Value can be modified
      Value++;

      // oValuePtr can be assigned
      oValuePtr = Value;

      // iValue can be modified
      oValuePtr += 1;

      // Return value can be modified
      return ++oValuePtr;
   }

   const int* TestClass::PointerMethod4(const int* Value)
   {
      // Value cannot be modified
      Value++;

      // oValuePtr *cannot* be assigned
      // const int* to int*
      oValuePtr = Value;

      // oValuePtr can be modified
      oValuePtr += 1;

      // Return value can be modified
      return ++oValuePtr;
   }

   const int* TestClass::PointerMethod5(const int* Value) const
   {
      // Value can be modified
      ++Value;

      // oValuePtr *cannot* be assigned
      // const int* to int* const
      // Access through a const object
      oValuePtr = Value;

      // oValuePtr *cannot* be modified
      // Access through a const object
      oValuePtr += 1;

      // Return value *cannot* be modified
      return ++oValuePtr;
   }
};

Sper că vă ajută!