C ++ Const Usage Explanation


Risposte:


77

Leggi questo: https://isocpp.org/wiki/faq/const-correctness

Il finale constsignifica che la funzione Method3non modifica i membri non modificabili della sua classe.

const int* constindica un puntatore costante a una costante int: cioè un puntatore che non può essere modificato, a un int che non può essere modificato: l'unica differenza tra questo ed const int&è che può esserenull

const int* const&indica un riferimento a un puntatore costante a una costante int. Di solito i puntatori non vengono passati per riferimento; const int* &ha più senso perché significherebbe che il puntatore potrebbe essere cambiato durante la chiamata al metodo, che sarebbe l'unica ragione per cui posso vedere per passare un puntatore per riferimento, const int* const&è a tutti gli effetti lo stesso const int* consttranne che probabilmente è meno efficiente poiché i puntatori sono tipi di dati semplici (POD) e questi dovrebbero, in generale, essere passati per valore.


103

È più facile da capire se lo riscrivi come completamente equivalente

// 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;

poi leggilo da destra a sinistra.

# 5 dice che l'intera dichiarazione di funzione a sinistra è const, il che implica che questa è necessariamente una funzione membro piuttosto che una funzione libera.

# 4 dice che il puntatore a sinistra è const(non può essere modificato per puntare a un indirizzo diverso).

# 3 dice che il inta sinistra è const(non può essere cambiato per avere un valore diverso).

# 2 dice che il puntatore a sinistra è const.

# 1 dice che inta sinistra è const.

Mettendo tutto insieme, puoi leggerlo come una constfunzione membro denominata Method3che prende un riferimento a un constpuntatore a un int const(o a const int, se preferisci) e restituisce un constpuntatore a un int const( const int).

(Nb # 2 è del tutto superfluo .)


22

Prima di tutto const Tè equivalente a T const.

const int* constè quindi equivalente a int const * const.

Quando si leggono espressioni contenenti molti consttoken e puntatori, provare sempre a leggerle da destra a sinistra (dopo aver applicato la trasformazione sopra). Quindi in questo caso il valore restituito è un puntatore const a una constint . Fare il puntatore stesso constnon ha senso qui poiché il valore restituito non è un lvalue che potrebbe essere modificato. Fare le punte const, tuttavia, garantisce che il chiamante non possa modificare il int(o l'array di ints) restituito da Method3.

const int*const&diventa int const*const&, quindi è un riferimento a un puntatore const a un constint . Anche il passaggio di un puntatore const tramite riferimenti male non ha senso: non è possibile modificare il valore di riferimento poiché il puntatore è conste i riferimenti e i puntatori occupano lo stesso spazio di archiviazione, quindi non ci sono risparmi di spazio.

L'ultima constindica che il metodo non modifica l' thisoggetto. Il thispuntatore all'interno del corpo del metodo avrà la dichiarazione (teorica) T const * const this. Ciò significa che un const T*oggetto potrà chiamare T::Method3().


2
Votando questo (e la risposta simile di ildjarn), in parte per aver sottolineato che l'intera cosa ha più senso se non metti la prima consts all'inizio della frase. Questo è precisamente il motivo per cui penso che sia una cattiva pratica da mettere constlì, anche se la lingua lo consente, ed è l'uso più comune.
TED

12

Un modo semplice per ricordare le regole di constè pensarlo in questo modo: si constapplica alla cosa alla sua sinistra, a meno che non ci sia nulla alla sua sinistra.

Quindi, nel caso di const int * const, la prima const non ha nulla alla sua sinistra, quindi si applica a inte la seconda ha qualcosa alla sua sinistra, quindi si applica al puntatore.

Questa regola ti dice anche cosa succederebbe nel caso in cui lo hai const int const *. Poiché entrambe le const si applicano a intquesta espressione è ridondante e quindi non valida.


3
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 */

3

Mi piace usare il metodo "orologio" o "spirale" in cui a partire dal nome dell'identificatore (in questo caso Method3) leggi avanti e indietro da sinistra a destra-indietro a sinistra, ecc. Per decodificare convenzioni di denominazione. Quindi const int* const Method3(const int* const&) constè un metodo di classe che non cambia alcun membro della classe (di qualche classe senza nome) e prende un riferimento costante a un puntatore che punta a una costante inte restituisce un puntatore costante a una costanteint .

Spero che questo ti aiuti,

Jason


2

Un modo semplice per ricordare il const in C ++ è quando vedi del codice in forma come:

XXX const;
const YYY;

XXX, YYY sarà una componente costante,
XXX constform:

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

const YYY modulo:

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

Le persone di solito usano questi tipi. Quando vedi "const&"da qualche parte, non sentirti confuso, const sta descrivendo qualcosa prima di se stesso. quindi la risposta a questo problema è ovvia ora.

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

2

Voglio solo menzionare che const int* const&è davvero un riferimento costante a const int*. Per esempio:

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'

È anche il caso di int* const&, Che significa: "Un riferimento costante a int*".
Ma const int*&è un riferimento non costante a const int*.
Spero che questo ti aiuti.


1

Leggere da destra a sinistra facilita la comprensione dei modificatori.

Un metodo const che accetta un riferimento a un puntatore const a un const int chiamato Method3che restituisce un puntatore const a un const int.

  1. Un metodo const non può modificare i membri (a meno che non siano esplicitamente mutable)
  2. Un puntatore const non può essere modificato per puntare a qualcos'altro
  3. Un const int (o qualsiasi altro tipo) non può essere modificato

1

const # 1: il puntatore restituito da Method3 fa riferimento a un const int.

const # 2: il valore del puntatore restituito dalla funzione stessa è const. Questa è una const inutile (sebbene grammaticalmente valida), perché il valore restituito da una funzione non può essere un valore l.

const # 3: il tipo di puntatore passato per riferimento alla funzione punta a un const int.

const # 4: il valore del puntatore passato per riferimento alla funzione è di per sé un puntatore const. Dichiarare un valore che viene passato a una funzione come const sarebbe normalmente inutile, ma questo valore viene passato per riferimento, quindi può essere significativo.

const # 5: la funzione (presumibilmente una funzione membro) è const, il che significa che non è consentito (a) assegnare nuovi valori a nessun membro dell'oggetto di cui fa parte o (b) chiamare una funzione membro non const sull'oggetto o su uno dei suoi membri.


0
  • const alla fine del metodo c'è il qualificatore che indica che lo stato dell'oggetto non verrà modificato.

  • const int*const&significa ricevere per riferimento un puntatore const a una posizione const. Non può né cambiare per puntare a una posizione diversa né cambiare il valore a cui punta.

  • const int*const è il valore di ritorno che è anche un puntatore costante a una posizione costante.


0

Alcuni esempi potrebbero essere utili per dimostrare questo concetto, più sono e meglio è.

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;
   }
};

Spero che aiuti!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.