right - int* c++




Was ist der Unterschied zwischen const int*, const int*const und int const*? (9)

  1. Konstante Referenz:

    Eine Referenz auf eine Variable (hier int), die konstant ist. Wir übergeben die Variable hauptsächlich als Referenz, weil Referenzen kleiner sind als der tatsächliche Wert, aber es gibt einen Nebeneffekt, und zwar deshalb, weil es wie ein Alias ​​für die tatsächliche Variable ist. Wir können die Hauptvariable versehentlich durch unseren vollen Zugriff auf den Alias ​​ändern, also machen wir es konstant, um diesen Nebeneffekt zu verhindern.

    int var0 = 0;
    const int &ptr1 = var0;
    ptr1 = 8; // Error
    var0 = 6; // OK
    
  2. Konstante Zeiger

    Sobald ein konstanter Zeiger auf eine Variable zeigt, kann er nicht auf eine andere Variable zeigen.

    int var1 = 1;
    int var2 = 0;
    
    int *const ptr2 = &var1;
    ptr2 = &var2; // Error
    
  3. Zeiger auf konstant

    Ein Zeiger, durch den man den Wert einer Variablen, auf die er zeigt, nicht ändern kann, ist als Zeiger auf die Konstante bekannt.

    int const * ptr3 = &var2;
    *ptr3 = 4; // Error
    
  4. Konstanter Zeiger auf eine Konstante

    Ein konstanter Zeiger auf eine Konstante ist ein Zeiger, der weder die Adresse ändern kann, auf die er zeigt, noch den Wert, der an dieser Adresse beibehalten wird.

    int var3 = 0;
    int var4 = 0;
    const int * const ptr4 = &var3;
    *ptr4 = 1;     // Error
     ptr4 = &var4; // Error
    

Ich vermassle immer, wie man const int* , const int * const und int const * richtig benutzt. Gibt es eine Reihe von Regeln, die definieren, was Sie tun können und was nicht?

Ich möchte alle Do's und alle Verbote in Bezug auf Aufgaben, Weitergabe an die Funktionen usw. kennen.


Die C- und C ++ - Deklarationssyntax wurde von den ursprünglichen Designern wiederholt als fehlgeschlagenes Experiment beschrieben.

Benennen wir stattdessen den Typ "Zeiger auf Type "; Ich werde es Ptr_ :

template< class Type >
using Ptr_ = Type*;

Jetzt ist Ptr_<char> ein Zeiger auf char .

Ptr_<const char> ist ein Zeiger auf const char .

Und const Ptr_<const char> ist ein const Zeiger auf const char .

Dort.


Dies betrifft hauptsächlich die zweite Zeile: Best Practices, Zuweisungen, Funktionsparameter usw.

Allgemeine Übung. Versuche alles so zu machen wie du kannst. Oder anders ausgedrückt: Machen Sie alles zu Beginn mit const , und entfernen Sie dann genau die minimale Anzahl von const notwendig sind, damit das Programm funktionieren kann. Dies wird eine große Hilfe sein, um die Korrektheit der Korrektheit zu erreichen, und wird dazu beitragen, dass kleine Fehler nicht eingeführt werden, wenn Leute versuchen, Dinge zuzuordnen, die sie nicht verändern sollen.

Vermeide const_cast <> wie die Pest. Es gibt ein oder zwei legitime Anwendungsfälle dafür, aber sie sind sehr selten und weit entfernt. Wenn Sie versuchen, ein const Objekt zu ändern, werden Sie viel besser darin sein, im ersten Schritt den const zu finden und die Sache zu besprechen, um einen Konsens darüber zu finden, was passieren soll.

Was sehr gut zu Aufgaben führt. Sie können nur dann etwas zuweisen, wenn es nicht konstant ist. Wenn Sie etwas const zuweisen möchten, siehe oben. Denken Sie daran, dass in den Deklarationen int const *foo; und int * const bar; verschiedene Dinge sind const - andere Antworten hier haben dieses Problem bewundernswert abgedeckt, also werde ich nicht darauf eingehen.

Funktionsparameter:

Pass by value: zB void func(int param) dir am einen oder anderen Ort am aufrufenden Ort egal. Es kann argumentiert werden, dass es Fälle gibt, in denen die Funktion als void func(int const param) aber keine Auswirkungen auf den Aufrufer hat, sondern nur auf die Funktion selbst, da der übergebene Wert von der Funktion nicht geändert werden kann der Anruf.

Pass by reference: zB void func(int &param) Jetzt macht es einen Unterschied. Wie gerade deklariert, darf param ändern, und jede aufrufende Seite sollte bereit sein, mit den Konsequenzen fertig zu werden. Das Ändern der Deklaration in void func(int const &param) ändert den Vertrag und garantiert, dass func nun param nicht ändern param , was param , dass was zurückgegeben wird, was wieder herauskommt. Wie andere bemerkt haben, ist dies sehr nützlich, um ein großes Objekt, das Sie nicht ändern möchten, billig zu übergeben. Das Übergeben einer Referenz ist viel billiger als das Übergeben eines großen Objekts nach Wert.

Pass-by-Pointer: zB void func(int *param) und void func(int const *param) Diese beiden sind ziemlich gleichbedeutend mit ihren Referenzgegenstücken, mit der Einschränkung, dass die aufgerufene Funktion nun auf nullptr prüfen nullptr außer es gibt eine andere vertragliche Garantie versichert func dass es niemals ein nullptr in param .

Stellungnahme zu diesem Thema. Die Richtigkeit in einem solchen Fall zu beweisen, ist höllisch schwierig, es ist einfach zu leicht, einen Fehler zu machen. nullptr also keine nullptr und überprüfe immer die nullptr auf nullptr . Sie werden sich Schmerzen und Leiden ersparen und auf lange Sicht schwer Fehler finden. Und was die Kosten des Schecks anbelangt, ist es spottbillig, und in Fällen, in denen die statische Analyse, die in den Compiler eingebaut ist, es handhaben kann, wird der Optimierer es trotzdem vermeiden. Aktivieren Sie die Link-Timecode-Generierung für MSVC oder WOPR (glaube ich) für GCC, und Sie erhalten es programmweit, dh sogar in Funktionsaufrufen, die eine Quellcode-Modulgrenze überschreiten.

Am Ende des Tages macht all das einen sehr soliden Fall, um Referenzen auf Zeiger immer vorzuziehen. Sie sind rundum sicherer.


Diese Frage zeigt genau, warum ich die Dinge so mache, wie ich in meiner Frage erwähnt habe .

Kurz gesagt, ich finde den einfachsten Weg, sich an die Regel zu erinnern, dass das "const" nach der Sache geht, auf die es zutrifft. In Ihrer Frage bedeutet "int const *" also, dass das int konstant ist, während "int * const" bedeutet, dass der Zeiger konstant ist.

Wenn jemand entscheidet, es ganz vorne zu setzen (zB: "const int *"), dann gilt das als besondere Ausnahme für die Sache danach.

Viele Leute benutzen diese spezielle Ausnahme gerne, weil sie denken, dass sie schöner aussieht. Ich mag es nicht, weil es eine Ausnahme ist und somit Dinge verwirrt.


Es gibt viele andere subtile Punkte, die die const-Korrektheit in C ++ umgeben. Ich nehme an, die Frage hier war einfach C, aber ich werde einige verwandte Beispiele geben, da das Tag C ++ ist:

  • Sie übergeben oft große Argumente wie Strings als TYPE const & die verhindern, dass das Objekt modifiziert oder kopiert wird. Beispiel:

    TYPE& TYPE::operator=(const TYPE &rhs) { ... return *this; }

    Aber TYPE & const ist bedeutungslos, weil Referenzen immer konstant sind.

  • Sie sollten immer Klassenmethoden beschriften, die die Klasse nicht als const ändern, andernfalls können Sie die Methode nicht aus einem TYPE const & reference aufrufen. Beispiel:

    bool TYPE::operator==(const TYPE &rhs) const { ... }

  • Es gibt allgemeine Situationen, in denen sowohl der Rückgabewert als auch die Methode const sein sollten. Beispiel:

    const TYPE TYPE::operator+(const TYPE &rhs) const { ... }

    Tatsächlich dürfen const-Methoden keine internen Klassendaten als Referenz-zu-nicht-konstant zurückgeben.

  • Als Ergebnis muss man oft sowohl eine const als auch eine nicht konstante Methode erstellen, die const overloading verwendet. Zum Beispiel, wenn Sie definieren T const& operator[] (unsigned i) const; , dann wirst du wahrscheinlich auch die nicht-konstante Version erhalten wollen, die gegeben ist durch:

    inline T& operator[] (unsigned i) { return const_cast<char&>( static_cast<const TYPE&>(*this)[](i) ); }

Afaik, es gibt keine Konst-Funktionen in C, Nicht-Member-Funktionen können nicht selbst in C ++ const sein, const-Methoden können Nebenwirkungen haben und der Compiler kann keine const-Funktionen verwenden, um doppelte Funktionsaufrufe zu vermeiden. In der Tat könnte sogar eine einfache int const & reference den Wert, auf den sie sich bezieht, an anderer Stelle ändern.


Es ist einfach, aber knifflig. Bitte beachten Sie, dass wir das const Qualifikationsmerkmal mit einem beliebigen Datentyp ( int , char , float usw.) vertauschen können.

Lassen Sie uns die folgenden Beispiele sehen.

const int *p ==> *p ist schreibgeschützt [ p ist ein Zeiger auf eine konstante ganze Zahl]

int const *p ==> *p ist schreibgeschützt [ p ist ein Zeiger auf eine konstante ganze Zahl]

int *p const ==> Falsche Aussage. Compiler löst einen Syntaxfehler aus.

int *const p ==> p ist schreibgeschützt [ p ist ein konstanter Zeiger auf eine Ganzzahl]. Da der Zeiger p hier schreibgeschützt ist, sollten Deklaration und Definition an der gleichen Stelle stehen.

const int *p const ==> Falsche Aussage. Compiler löst einen Syntaxfehler aus.

const int const *p ==> *p ist schreibgeschützt

const int *const p1 ==> *p und p sind schreibgeschützt [ p ist ein konstanter Zeiger auf eine konstante ganze Zahl]. Da der Zeiger p hier schreibgeschützt ist, sollten Deklaration und Definition an der gleichen Stelle stehen.

int const *p const ==> Falsche Aussage. Compiler löst einen Syntaxfehler aus.

int const int *p ==> Falsche Aussage. Compiler löst einen Syntaxfehler aus.

int const const *p ==> *p ist schreibgeschützt und entspricht int const *p

int const *const p ==> *p und p sind schreibgeschützt [ p ist ein konstanter Zeiger auf eine konstante ganze Zahl]. Da der Zeiger p hier schreibgeschützt ist, sollten Deklaration und Definition an der gleichen Stelle stehen.


Ich denke, dass hier schon alles beantwortet ist, aber ich möchte nur hinzufügen, dass du dich vor typedef hüten typedef ! Sie sind nicht nur Textersatz.

Beispielsweise:

typedef char *ASTRING;
const ASTRING astring;

Der Typ von astring ist char * const , nicht const char * . Dies ist einer der Gründe, warum ich immer dazu tendiere, const rechts vom Typ zu setzen, und niemals am Anfang.


Ich hatte dieselben Zweifel wie Sie, bis ich vom C ++ - Guru Scott Meyers auf dieses book . Lesen Sie den dritten Punkt in diesem Buch, in dem er ausführlich über die Verwendung von const spricht.

Folge einfach diesem Rat

  1. Wenn das Wort const auf der linken Seite des const erscheint, ist darauf hingewiesen, was konstant ist
  2. Wenn das Wort const rechts vom Stern erscheint, ist der Zeiger selbst konstant
  3. Wenn const auf beiden Seiten erscheint, sind beide konstant

Wie so ziemlich jeder betont hat:

Was ist der Unterschied zwischen const X* p , X* const p und const X* const p ?

Sie müssen Zeigerdeklarationen von rechts nach links lesen.

  • const X* p bedeutet "p zeigt auf ein X, das const ist": Das X-Objekt kann nicht über p geändert werden.

  • X* const p bedeutet "p ist ein konstanter Zeiger auf ein X, das nicht konstant ist": Sie können den Zeiger p selbst nicht ändern, aber Sie können das X-Objekt über p ändern.

  • const X* const p bedeutet "p ist ein const-Zeiger auf ein X, das const ist": Sie können weder den Zeiger p selbst ändern noch das X-Objekt über p ändern.





const