Spiegazione dell’uso di Const C ++

const int* const Method3(const int* const&) const; 

Qualcuno può spiegare l’uso di ciascuna delle const?

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

Il const finale indica che la funzione Method3 non modifica i membri non mutabili della sua class.

const int* const indica 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 e const int& è che può essere null

const int* const& significa un riferimento a un puntatore costante a una costante int. Solitamente 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 passare un puntatore per riferimento, const int* const& è a tutti gli effetti lo stesso come const int* const eccetto che è probabilmente meno efficiente in quanto i puntatori sono semplici vecchi dati (POD) e questi dovrebbero, in generale, essere passati per valore.

È più facile 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; 

quindi leggerlo 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 cambiato per puntare a un indirizzo diverso).

# 3 dice che l’ int a sinistra è const (non può essere cambiato per avere un valore diverso).

# 2 dice che il puntatore a sinistra è const .

# 1 dice che l’ int a sinistra è const .

Mettendo tutto insieme, puoi leggere questo come una funzione membro const denominata Method3 che prende un riferimento a un puntatore const a un int const (o a const int , se preferisci) e restituisce un puntatore const a un int const ( const int ).

Innanzitutto const T è equivalente a T const .

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

Durante la lettura di espressioni con molti token const e puntatori in esse, cerca sempre di leggerle da destra a sinistra (dopo aver applicato la trasformazione sopra). Quindi in questo caso il valore di ritorno è un puntatore const a un const int . Rendere il puntatore stesso const non ha senso in quanto il valore di ritorno non è un lvalue che potrebbe essere modificato. Rendere il pointee const , tuttavia, garantisce che il chiamante non possa modificare l’ int (o la matrice di int s) restituita da Method3 .

const int*const& diventa int const*const& , quindi è un riferimento a un puntatore const a un const int . Passare un puntatore const per riferimento al maschio non ha alcun senso – non è ansible modificare il valore di riferimento poiché il puntatore è const e i riferimenti ei puntatori occupano lo stesso spazio di archiviazione, quindi non vi sono nemmeno risparmi di spazio.

L’ultima const indica che il metodo non modifica this object. Il puntatore all’interno del corpo del metodo avrà la dichiarazione (teorica) T const * const this . Ciò significa che un object const T* sarà in grado di chiamare T::Method3() .

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

Quindi nel caso di const int * const , il primo const non ha nulla alla sua sinistra, quindi si applica a int e il secondo ha qualcosa a sinistra, quindi si applica al puntatore.

Questa regola ti dice anche cosa succederebbe nel caso in cui tu abbia const int const * . Poiché entrambi i const si applicano a int questa espressione è ridondante e quindi non valida.

Mi piace usare il metodo “orologio” o “spirale” dove, partendo dal nome dell’identificatore (in questo caso Method3 ), si legge avanti e indietro da sinistra a destra, da sinistra a destra, ecc. Per decodificare le convenzioni di denominazione. Quindi const int* const Method3(const int* const&) const è un metodo di class che non modifica alcun membro di class (di qualche class non denominata) e prende un riferimento costante a un puntatore che punta a una costante int e restituisce un puntatore costante a costante int .

Spero che questo ti aiuti,

Jason

 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. eg you cannot say `++pointer` */ &) const; /* this method does not modify the instance/object which implements the method */ 

Leggere da destra a sinistra facilita la comprensione dei modificatori.

Un metodo const che prende un riferimento a un puntatore const su un const const chiamato Method3 che restituisce un puntatore const a un const int.

  1. Un metodo const non può modificare i membri (a meno che non siano modificabili in modo esponenziale)
  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

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

const # 2: il valore del puntatore restituito dalla funzione stessa è const. Questo è un const inutile (anche se grammaticalmente valido), 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 è, a sua volta, un puntatore const. Dichiarare un valore che viene passato a una funzione come const normalmente non ha senso, ma questo valore viene passato per riferimento, quindi può essere significativo.

const # 5: La funzione (presumibilmente una funzione membro) è const, nel senso che non è consentito (a) assegnare nuovi valori a qualsiasi membro dell’object di cui fa parte o (b) chiama una funzione membro non const sull’object o su uno dei suoi membri.

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

 XXX const; const YYY; 

XXX, YYY sarà una componente costante,
Forma XXX const :

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

forma const YYY :

 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 

Voglio solo menzionare che const int* const& è in effetti 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.

  • const alla fine del metodo è il qualificatore che indica lo stato dell’object non verrà modificato.

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

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

Alcuni esempi potrebbero essere utili per dimostrare questo concetto, tanto più il meglio è 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; } }; 

Spero che aiuti!