Erklärung zur Verwendung von C ++ - Konstanten

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

Kann jemand die Verwendung der einzelnen const erklären?

RoR
quelle
27
Ich mag diese Methode zum Entschlüsseln komplizierter Deklarationen sehr: c-faq.com/decl/spiral.anderson.html
Jason

Antworten:

77

Lesen Sie dies: https://isocpp.org/wiki/faq/const-correctness

Das letzte constbedeutet, dass die Funktion Method3die nicht veränderlichen Mitglieder ihrer Klasse nicht ändert.

const int* constbedeutet einen konstanten Zeiger auf eine Konstante int: dh einen Zeiger, der nicht geändert werden kann, auf einen int, der nicht geändert werden kann: Der einzige Unterschied zwischen dieser und der const int&besteht darin, dass dies möglich istnull

const int* const&bedeutet eine Referenz auf einen konstanten Zeiger auf eine Konstante int. Normalerweise werden Zeiger nicht als Referenz übergeben. const int* &Dies ist sinnvoller, da dies bedeuten würde, dass der Zeiger während des Methodenaufrufs geändert werden könnte. Dies ist der einzige Grund, warum ich sehe, dass ein Zeiger als Referenz übergeben const int* const&wird. Dies ist in jeder Hinsicht dasselbe, const int* constaußer dass er wahrscheinlich weniger effizient ist Da Zeiger einfache POD-Typen (Old Data) sind, sollten diese im Allgemeinen als Wert übergeben werden.

Satnhak
quelle
103

Es ist einfacher zu verstehen, wenn Sie dies als das völlig Äquivalent umschreiben

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

dann lies es von rechts nach links.

# 5 besagt, dass die gesamte Funktionsdeklaration links ist const, was impliziert, dass dies notwendigerweise eine Mitgliedsfunktion und keine freie Funktion ist.

# 4 besagt, dass der Zeiger links ist const(darf nicht geändert werden, um auf eine andere Adresse zu zeigen).

# 3 besagt, dass das intlinks ist const(darf nicht geändert werden, um einen anderen Wert zu haben).

# 2 sagt, dass der Zeiger nach links ist const.

# 1 sagt, dass das intauf der linken Seite ist const.

Wenn Sie alles zusammenfassen, können Sie dies als eine constMitgliedsfunktion mit dem Namen lesen Method3, die einen Verweis auf einen constZeiger auf ein int const(oder ein const int, wenn Sie es vorziehen) verwendet und einen constZeiger auf ein int const( const int) zurückgibt .

(Nb # 2 ist völlig überflüssig .)

ildjarn
quelle
22

Erstens const Tist gleichbedeutend mit T const.

const int* constist daher gleichbedeutend mit int const * const.

constVersuchen Sie beim Lesen von Ausdrücken mit vielen Token und Zeigern immer, sie von rechts nach links zu lesen (nachdem Sie die obige Transformation angewendet haben). In diesem Fall ist der Rückgabewert ein const-Zeiger auf eine constint . Das constErstellen des Zeigers selbst macht hier keinen Sinn, da der Rückgabewert kein Wert ist, der geändert werden könnte. Durch das Erstellen des Pointees constwird jedoch garantiert, dass der Aufrufer das von zurückgegebene int(oder Array von ints) nicht ändern darf Method3.

const int*const&wird int const*const&, so ist es eine Referenz auf einen const Zeiger auf eine constint . Das Übergeben eines const-Zeigers durch männliche Referenzen macht ebenfalls keinen Sinn - Sie können den referenzierten Wert nicht ändern, da der Zeiger ist constund Referenzen und Zeiger den gleichen Speicherplatz belegen, sodass auch keine Platzersparnis entsteht.

Der letzte constgibt an, dass die Methode das thisObjekt nicht ändert . Der thisZeiger innerhalb des Methodenkörpers hat die (theoretische) Deklaration T const * const this. Dies bedeutet, dass ein const T*Objekt aufrufen kann T::Method3().

Alexander Gessler
quelle
2
Stimmen Sie dies (und die ähnliche Antwort von ildjarn) ab, teilweise um darauf hinzuweisen, dass das Ganze sinnvoller ist, wenn Sie nicht das erste consts an die Spitze der Phrase setzen. Dies ist genau der Grund, warum ich denke, dass es eine schlechte Praxis ist, sie constdort zu platzieren, obwohl die Sprache dies zulässt und es die häufigste Verwendung ist.
TED
12

Eine einfache Möglichkeit, sich an die Regeln von zu erinnern, constbesteht darin, folgendermaßen darüber nachzudenken: constGilt für das Ding auf der linken Seite, es sei denn, es befindet sich nichts auf der linken Seite.

Im Fall von const int * consthat die erste Konstante nichts auf der linken Seite, also gilt sie für intund die zweite hat etwas auf der linken Seite, also gilt sie für den Zeiger.

Diese Regel sagt Ihnen auch, was in dem Fall passieren würde, in dem Sie haben const int const *. Da beide Konstanten für intdiesen Ausdruck gelten, ist er redundant und daher ungültig.

Yony
quelle
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 */
Justin
quelle
3

Ich verwende gerne die "Clock" - oder "Spiral" -Methode, bei der Sie ausgehend vom Bezeichnernamen (in diesem Fall Method3) von links nach rechts, von links nach links usw. hin und her lesen, um zu dekodieren Regeln der Namensgebung. Dies const int* const Method3(const int* const&) constgilt auch für eine Klassenmethode, die keine Klassenmitglieder (einer nicht benannten Klasse) ändert und einen konstanten Verweis auf einen Zeiger verwendet, der auf eine Konstante zeigt intund einen konstanten Zeiger auf eine Konstante zurückgibt int.

Hoffe das hilft,

Jason

Jason
quelle
2

Eine einfache Möglichkeit, sich an die Konstante in C ++ zu erinnern, besteht darin, Code in folgender Form zu sehen:

XXX const;
const YYY;

XXX, JJJ wird eine konstante Komponente sein,
XXX constForm:

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

const YYY bilden:

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

Leute benutzen normalerweise diese Typen. Wenn Sie "const&"irgendwo sehen, fühlen Sie sich nicht verwirrt, const beschreibt etwas vor sich. Die Antwort auf dieses Problem liegt nun auf der Hand.

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

Ich möchte nur erwähnen, dass dies const int* const&in der Tat ein ständiger Hinweis ist const int*. Beispielsweise:

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'

Es ist auch der Fall für int* const&, was bedeutet: "Ein ständiger Verweis auf int*".
Ist const int*&aber ein nicht konstanter Verweis auf const int*.
Hoffe das hilft.

MrDetective
quelle
1

Das Lesen von rechts nach links erleichtert das Verständnis von Modifikatoren.

Eine const-Methode, die einen Verweis auf einen const-Zeiger auf eine aufgerufene const int verwendet, Method3die einen const-Zeiger auf eine const int zurückgibt.

  1. Eine const-Methode kann keine Mitglieder ändern (es sei denn, sie sind explizit mutable)
  2. Ein const-Zeiger kann nicht geändert werden, um auf etwas anderes zu verweisen
  3. Ein const int (oder ein anderer Typ) kann nicht geändert werden
Nick Strupat
quelle
1

const # 1: Der von Methode3 zurückgegebene Zeiger verweist auf eine const int.

const # 2: Der von der Funktion selbst zurückgegebene Zeigerwert ist const. Dies ist eine nutzlose Konstante (obwohl grammatisch gültig), da der Rückgabewert einer Funktion kein l-Wert sein kann.

const # 3: Der Zeigertyp, der als Referenz auf die Funktion übergeben wird, zeigt auf eine const int.

const # 4: Der Zeigerwert, der als Verweis auf die Funktion übergeben wird, ist selbst ein const-Zeiger. Das Deklarieren eines Werts, der an eine Funktion als const übergeben wird, ist normalerweise sinnlos, aber dieser Wert wird als Referenz übergeben, sodass er sinnvoll sein kann.

const # 5: Die Funktion (vermutlich eine Mitgliedsfunktion) ist const, was bedeutet, dass es nicht erlaubt ist, (a) Mitgliedern des Objekts, zu dem sie gehört, neue Werte zuzuweisen oder (b) eine Nicht-const-Mitgliedsfunktion aufzurufen auf dem Objekt oder einem seiner Mitglieder.

Jollymorph
quelle
0
  • const Am Ende der Methode befindet sich das Qualifikationsmerkmal, das angibt, dass der Status des Objekts nicht geändert wird.

  • const int*const&bedeutet, dass durch Verweisen ein const-Zeiger auf eine const-Position empfangen wird. Es kann weder geändert werden, um auf eine andere Position zu zeigen, noch den Wert ändern, auf den es zeigt.

  • const int*const ist der Rückgabewert, der auch ein konstanter Zeiger auf eine konstante Position ist.

Mahesh
quelle
0

Ein paar Beispiele könnten nett sein, um dieses Konzept zu demonstrieren, je mehr desto besser 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;
   }
};

Ich hoffe das hilft!

Rastus7
quelle