Dabei geht es hauptsächlich um die zweite Zeile: bewährte Verfahren, Zuweisungen, Funktionsparameter usw.
Allgemeine Praxis. Versuchen Sie, alles const
die Sie können. Oder anders ausgedrückt: Machen Sie alles const
zu beginnen, und dann genau die Mindestmenge von const
die notwendig sind, damit das Programm funktioniert. Dies wird eine große Hilfe bei der Erreichung von const-Korrektheit sein und wird dazu beitragen, dass subtile Fehler nicht eingeführt werden, wenn Leute versuchen, in Dinge zuzuweisen, die sie nicht ändern sollen.
Vermeiden Sie const_cast<> wie die Pest. Es gibt ein oder zwei legitime Anwendungsfälle dafür, aber die sind sehr selten und weit entfernt. Wenn Sie versuchen, eine const
Objekt zu finden, ist es viel besser, denjenigen zu finden, der es angemeldet hat const
und besprechen Sie die Angelegenheit mit ihnen, um einen Konsens darüber zu erzielen, was geschehen soll.
Das führt sehr gut zu den Aufträgen. Sie können etwas nur zuweisen, wenn es nicht konstant ist. Wenn Sie in etwas zuweisen wollen, das const ist, siehe oben. Denken Sie daran, dass in den Deklarationen int const *foo;
y int * const bar;
verschiedene Dinge sind const
- Die anderen Antworten hier haben dieses Thema bereits ausführlich behandelt, so dass ich nicht näher darauf eingehen werde.
Funktionsparameter:
Übergabe nach Wert: z.B. void func(int param)
Es ist Ihnen am Anruferstandort egal, was Sie tun. Es kann argumentiert werden, dass es Anwendungsfälle gibt, in denen die Funktion als void func(int const param)
aber das hat keine Auswirkungen auf den Aufrufer, sondern nur auf die Funktion selbst, da der übergebene Wert von der Funktion während des Aufrufs nicht geändert werden kann.
Übergabe durch Referenz: z.B. void func(int ¶m)
Jetzt macht es einen Unterschied. Wie gerade erklärt func
darf sich ändern param
und jede aufrufende Stelle sollte bereit sein, mit den Folgen umzugehen. Die Änderung der Deklaration in void func(int const ¶m)
den Vertrag ändert, und garantiert, dass func
kann nun nicht mehr ändern param
Das bedeutet, dass das, was hineingelangt, auch wieder herauskommt. Wie andere bereits festgestellt haben, ist dies sehr nützlich, um ein großes Objekt, das man nicht ändern möchte, kostengünstig zu übergeben. Die Übergabe einer Referenz ist viel billiger als die Übergabe eines großen Objekts als Wert.
Übergabe durch Zeiger: z.B. void func(int *param)
y void func(int const *param)
Diese beiden sind so gut wie gleichbedeutend mit ihren Referenz-Gegenstücken, mit dem Vorbehalt, dass die aufgerufene Funktion nun prüfen muss, ob nullptr
es sei denn, eine andere vertragliche Garantie sichert zu func
dass sie niemals eine nullptr
en param
.
Meinungsbeitrag zu diesem Thema. Der Nachweis der Korrektheit in einem solchen Fall ist höllisch schwierig, es ist einfach zu leicht, einen Fehler zu machen. Gehen Sie also kein Risiko ein, und überprüfen Sie Zeigerparameter immer auf nullptr
. Damit ersparen Sie sich auf lange Sicht Schmerzen und Leiden und schwer zu findende Bugs. Und was die Kosten für die Prüfung angeht, so ist sie spottbillig, und in Fällen, in denen die in den Compiler eingebaute statische Analyse sie bewältigen kann, wird der Optimierer sie ohnehin auslassen. Schalten Sie die Link Time Code Generation für MSVC oder WOPR (glaube ich) für GCC ein, und Sie erhalten sie programmweit, d.h. auch in Funktionsaufrufen, die eine Quellcode-Modulgrenze überschreiten.
Am Ende des Tages alle der oben genannten macht ein sehr solides Argument zu immer lieber Referenzen zu Zeigern. Sie sind einfach rundum sicherer.
256 Stimmen
Sie können die "Clockwise/Spiral Rule" um die meisten C- und C++-Deklarationen zu entschlüsseln.
76 Stimmen
cdecl.org ist eine großartige Website, die automatisch C-Deklarationen für Sie übersetzt.
11 Stimmen
@Calmarius: Beginnen Sie an der Stelle, an der sich der Typenname befindet bzw. befinden sollte, gehen Sie nach rechts, wenn Sie können, und nach links, wenn Sie müssen. .
int *(*)(char const * const)
. Beginnen Sie rechts von der eingeklammerten*
dann müssen wir nach links gehen:pointer
. Außerhalb der Klammern können wir nach rechts gehen:pointer to function of ...
. Dann müssen wir nach links gehen:pointer to function of ... that returns pointer to int
. Wiederholen Sie den Vorgang, um den Parameter zu erweitern (die...
) :pointer to function of (constant pointer to constant char) that returns pointer to int
. Wie würde die entsprechende einzeilige Erklärung in einer leicht lesbaren Sprache wie Pascal aussehen?3 Stimmen
@MarkKCowan In Pascal würde es etwa so lauten
function(x:^char):^int
. Dort sind Funktionstypen implizit ein Zeiger auf eine Funktion, so dass keine Notwendigkeit besteht, sie zu spezifizieren, und Pascal erzwingt keine const-Korrektheit. Es kann von links nach rechts gelesen werden.0 Stimmen
@Calmarius: In Pascal können komplexere Typen jedoch oft nicht in einem einzigen Ausdruck dargestellt werden, sondern müssen durch die Deklaration verschiedener einfacher Sub-Type-Ausdrücke zusammengesetzt werden.
13 Stimmen
Das erste, was links von "const" steht, ist das, was konstant ist. Wenn "const" das ist, was am weitesten links steht, dann ist das erste, was rechts davon steht, das, was konstant ist.
0 Stimmen
Obwohl viele gute Antworten gegeben werden, scheint es, dass der Teil der Frage, in dem es um die Frage geht, nicht beantwortet wird: "Übergabe an Funktionen" noch nicht wirklich beantwortet ist?
0 Stimmen
Ich frage mich z.B. immer noch, ob es jemals sinnvoll ist, eine Funktionsdeklaration f(const Class * const obj) anstelle von f(const Class * obj) zu haben? Bringt das zweite const in der ersten Deklaration überhaupt etwas? Ich würde sagen nein, da der Zeiger ohnehin als Wert übergeben wird
0 Stimmen
Wie kommt es, dass Ihr Name angezeigt wird, es aber so aussieht, als hätten Sie Ihr Konto selbst gelöscht?
1 Stimmen
ISO C++ FAQ : Was ist der Unterschied zwischen
const X* p
,X* const p
yconst X* const p
?0 Stimmen
Cdecl.org verwendet eine alte Version von cdecl; eine Version von cdecl, die modernes C und C++ versteht, finden Sie hier: github.com/paul-j-lucas/cdecl
0 Stimmen
@MarkKCowan Können Sie bitte einen Blick darauf werfen stackoverflow.com/questions/70921574/