Zu Beginn wissen Sie wahrscheinlich, dass const
damit entweder die Daten eines Objekts oder ein Zeiger nicht geändert werden können oder beides.
const Object* obj; // can't change data
Object* const obj; // can't change pointer
const Object* const obj; // can't change data or pointer
Sie können jedoch auch die folgende Syntax verwenden:
Object const *obj; // same as const Object* obj;
Das einzige, was wichtig zu sein scheint, ist, auf welcher Seite des Sterns Sie das const
Schlüsselwort setzen. Persönlich ziehe ich es vor, const
links vom Typ zu setzen, um anzugeben, dass die Daten nicht geändert werden können, da ich finde, dass sie in meiner Denkweise von links nach rechts besser lesbar sind, aber welche Syntax kam zuerst?
Noch wichtiger ist, warum gibt es zwei korrekte Möglichkeiten zur Angabe von const
Daten und in welcher Situation würden Sie eine über die andere bevorzugen oder benötigen, wenn überhaupt?
Bearbeiten:
Es klingt also so, als wäre dies eine willkürliche Entscheidung gewesen, als der Standard für die Interpretation von Dingen durch Compiler lange vor meiner Geburt ausgearbeitet wurde. Da const
es auf das angewendet wird, was sich links vom Schlüsselwort befindet (standardmäßig?), Vermutlich hat es keinen Schaden angerichtet, "Verknüpfungen" hinzuzufügen , um Schlüsselwörter und Typqualifizierer auf andere Weise anzuwenden, zumindest bis sich die Deklaration um ändert Analyse eines * oder & ...
Dies war auch in C der Fall, nehme ich an?
const
nach dem Typ hinzu, z. B.#define MAKE_CONST(T) T const
statt#define MAKE_CONST(T) const T
,MAKE_CONST(int *)
damit korrekt aufint * const
statt erweitert wirdconst int *
.Antworten:
Der Grund dafür, dass die Position
const
innerhalb von Spezifizierern vor einem Sternchen keine Rolle spielt, ist im Wesentlichen, dass die C-Grammatik von Kernighan und Ritchie auf diese Weise definiert wurde.Der Grund, warum sie die Grammatik auf diese Weise definiert haben, war wahrscheinlich, dass ihr C-Compiler die Eingabe von links nach rechts analysierte und die Verarbeitung jedes Tokens beendete, während er dies verbrauchte. Durch das Konsumieren des
*
Tokens wird der Status der aktuellen Deklaration in einen Zeigertyp geändert. Begegnungconst
nach*
bedeutet, dass dasconst
Qualifikationsmerkmal auf eine Zeigerdeklaration angewendet wird. Wenn Sie darauf stoßen, bevor*
das Qualifikationsmerkmal auf die Daten angewendet wird, auf die verwiesen wird.Da sich die semantische Bedeutung nicht ändert, wenn das
const
Qualifikationsmerkmal vor oder nach den Typspezifizierern angezeigt wird, wird es in beiden Fällen akzeptiert.Ein ähnlicher Fall tritt auf, wenn Funktionszeiger deklariert werden, wobei:
void * function1(void)
deklariert eine Funktion, die zurückgibtvoid *
,void (* function2)(void)
deklariert einen Funktionszeiger auf eine Funktion, die zurückgibtvoid
.Wiederum ist zu beachten, dass die Sprachsyntax einen Parser von links nach rechts unterstützt.
quelle
*
Compiler-Parser nicht weiß, dass es sich um einen Zeiger handelt, handelt es sich um eine Konstante für den Datenwert. Nach * bezieht es sich auf den konstanten Zeiger. Brillant. Und schließlich erklärt es, warum ichconst char
so gut kannchar const
.const
immer nach dem kommt, was es qualifiziert ... genau so, dass ich die Verarbeitung der Konstante immer sofort beenden kann, nachdem ich sie verbraucht habe. Dies scheint also ein Argument dafür zu sein , West-Const zu verbieten , anstatt es zuzulassen.++
Operator haben? "Der Satz", imho, half mir zu erkennen, dass es keinen bestimmten Grund gab, außer weil sie es konnten. Vielleicht würden sie heute eine andere Wahl treffen / vielleicht auch nicht.Die Regel lautet:
Ich bevorzuge die Verwendung von const rechts von der Sache, um const zu sein, nur weil es die "ursprüngliche" Art ist, wie const definiert wird.
Aber ich denke, das ist eine sehr subjektive Sichtweise.
quelle
Object const *
als Zeiger auf ein const-Objekt. Wenn Sieconst
das links platzieren, wird es als Zeiger auf ein Objekt gelesen, das const ist und nicht wirklich gut fließt.const
es sich nicht um eine Speicherklasse handelt, aber die Leute sind keine Parser).Ich bevorzuge die zweite Syntax. Es hilft mir, den Überblick darüber zu behalten, was konstant ist, indem ich die Typdeklaration von rechts nach links lese:
quelle
Object const* const
nichtconst const Object*
. "const" kann nicht links stehen, außer in dem speziellen Fall, in dem so viele Leute es absolut lieben. (Siehe Heide oben.)Die Reihenfolge der Schlüsselwörter in einer Deklaration ist nicht allzu fest. Es gibt viele Alternativen zu "der einen wahren Ordnung". So was
oder sollte es sein
??
quelle
decl-specifier-seq
eine Folge vondecl-specifier
s ist. Die Grammatik gibt keine Reihenfolge vor, und die Anzahl der Vorkommen für jedes Schlüsselwort ist nur durch einige semantische Regeln begrenzt (Sie können eine,const
aber zwei habenlong
:-)unsigned
ist ein Typ, der mitunsigned int
und identisch istint unsigned
.unsigned long
ist ein anderer Typ, der gleiche wieunsigned long int
undint long unsigned
. Sehen Sie das Muster?;)
. OK, dankestatic
das Durcheinander von Wörtern erweitern, aber erst kürzlich haben sich Compiler beschwert, dass diesstatic
an erster Stelle stehen muss.Die erste Regel besteht darin, das Format zu verwenden, das Ihre lokalen Codierungsstandards erfordern. Danach:
const
Wenn Sie die Front vorlegen, führt dies zu Verwirrung, wenn es sich um Typedefs handelt, z.Wenn Ihr Codierungsstandard Typedefs von Zeigern zulässt, sollte er wirklich darauf bestehen, die Konstante nach dem Typ zu setzen. In jedem Fall, aber wenn es auf den Typ angewendet wird, muss const dem folgen, wofür es gilt, daher spricht Kohärenz auch für die Konstante danach. Lokale Kodierungsrichtlinien übertreffen jedoch alle diese; Der Unterschied ist normalerweise nicht wichtig genug, um den gesamten vorhandenen Code zu ändern.
quelle
const std::string::const_iterator
auch für ein gutes Maßconst IntPtr p1
möglicherweise anderes bedeuten als "konstanter ganzzahliger Zeiger" (dh "konstanter Zeiger auf ganze Zahl")? Niemand, der bei klarem Verstand ist, selbst wenn er nicht weiß, wie erIntPtr
definiert ist, würde dasp1
für veränderlich halten. Und warum sollte jemand fälschlicherweise annehmen, dass dies*p1
unveränderlich ist? Wenn Sie die Konstante an einer anderen Stelle platzieren (z. B.IntPtr const p1
), ändert sich die Semantik überhaupt nicht.std::vector<T>::const_iterator
, wo es nicht der Iterator ist, der const ist, sondern worauf er zeigt).Es gibt historische Gründe, warum entweder links oder rechts akzeptabel ist. Stroustrup hatte C ++ bis 1983 const hinzugefügt , aber es schaffte es nicht bis C89 / C90 nach C.
In C ++ gibt es einen guten Grund, const immer rechts zu verwenden. Sie werden im Einklang überall da konstanten Elementfunktionen müssen auf diese Weise erklärt werden:
quelle
const int& getInt();
int& const getInt();
int const& getInt();
ist besser als das Äquivalent,const int& getInt();
während dasint& const getInt();
, mit dem Sie es vergleichen, überflüssig ist (Referenzen sind bereits const), obwohl es legal ist und normalerweise eine Warnung gibt. Wie auch immer, const on a member function ändert denthis
Zeiger in der Funktion vonFoo* const
toFoo const* const
.const
auf einer Mitgliedsfunktion bedeutet überhaupt nicht dasselbe - oder ist esvoid set(int)&;
eine Art Verweis auf eine Funktion?