Wozu bzw. wann löscht man
Kommt auf dein Programm an. Wann willst du die Eingaben vor dem nächsten Enter ignorieren? (zumindest für dein Beispiel ist Entfer, und auch nur max. 1000 Byte)
...
Zu const und constexpr, das ist etwas umständlicher. Vielleicht ist noch nicht alles der folgenden Sachen bekannt, aber ich schreibs trotzdem einmal auf...
Zuerst einmal ein paar mögliche Anwendungsfälle und Eigenschaften von const.
a) Variablen machen, die (nach der Initialisierung) nicht mehr verändert werden können
C++:
int a = 1;
int b= a + 1;
a= 2;
Hier, noch ohne const, ist das alles in Ordnung. EIne int-Variable wird gemacht und bekommt Wert 1, wird zum Rechnen für was anderes verwendet und bekommt später noch den Wert 2. Wenn a jetzt "const int a = 1;" wäre, wäre Zeile 2 zwar in Ordnung (a wird ja nicht verändert, nur zum Rechnen verwendet), aber Zeile drei würde Compilerfehler erzeugen.
Mach zB. Sinn für
Code:
const double pi = 3.14159388;
, weil wenn man versehentlich Code schreibt der Pi ändert bekommt man einen Fehler... (aber auch vieles mehr, so fixe Zahlenkonstanten sind bei Weitem nicht der einzige Grund)
Aber: Das alles bisher bedeutet nicht, dass der Wert der Variable immer 1 ist.
C++:
int funktion1()
{
int returnwert;
cin >> returnwert;
return returnwert;
}
...
const int a = funktion1();
Das ist genauso erlaubt. a bekommt seinen Wert durch eine Tastatureingabe, kann immer was anderes sein. const bedeutet "nur", dass es dann im restlichen Programm nicht mehr verändert werden kann.
Und eine weitere Falle
C++:
const int a = 1;
const int b;
b = 1;
a ist ok, b nicht. Es geht nicht darum, dass die "erste" Zuweisung erlaubt ist (schon deswegen, weil man bei Threads nicht immer ein "erstes" hat), sondern der Wert muss wirklich beim Anlegen der Variable schon reinkommen. Das "b=1" hier ist nicht erlaubt, und das Anlegen von b selber (const-Variable ohne Wert) liefert auch einen Fehler (nicht erlaubt weil es einfach keinen Sinn macht: Eine Variable, die nie einen Wert haben kann).
.
Außer, dass man vor Schlampigkeitsfehlern geschützt wird (wie bei pi oben, dass man sicher nicht ändern will), gibt es auch einen weiteren möglichen Vorteil: Geschwindigkeitsoptimierungen im Compiler EIn beliebter Teil davon:
C++:
int a = 1;
int b= a + 1;
a= 2;
Was in den Compiler reinprogrammiert ist kann in einfachen Situationen wie hier bestimmen, dass b 2 ist, und muss das Ausrechnen nicht ins Programm selber einbauen (damit spart man beim Ausführen vom Programm Zeit). Wenn zwischen Anlegen von a und b mehr Code ist kann der Compiler aber oft nicht sicher bestimmen, ob a noch immer 1 ist, und kann die Rechnung deshalb nicht einsparen. (Und auch kompliziertere Rechnungen sind ein Problem). (Btw., einen "perfekten" Compiler machen ist unmöglich, siehe Turings Halteproblem usw. Es gibt immer Codes, die einen Optimierer versagen lassen, egal wie gut er ist. Deshalb versucht man es auch gar nicht)
Wenn a jetzt const ist hilft das, weil sich der Optimierer sicher sein kann, dass sich a nicht ändert. Teilweise können dadurch dann eben noch schnellere Programme erzeugt werden.
.
Und noch ein weiteres Thema, falls Pointer schon geläufig sind: a auf 2 verändern kann über Umwege ja auch so gemacht werden:
C++:
int a = 1;
int *p = &a;
*p= 2;
Falls a const ist, gibts hier eine Reihe von Problemen: a zu ändern ist nämlich auch so nicht erlaubt, und der Compiler kann aber nicht in jedem Fall einen Fehler melden.
Warum nicht immer meldbar: Wieder mal das Halteproblem: Der Compiler kann bei großen/komplexen Programmen nicht immer mitverfolgen, ob p jetzt auf eine const-Variable zeigt oder nicht.
Warum nicht erlaubt Teil 1: Optimierungen, wieder. const heißt const. Die 2 technisch den Arbeitsspeicher schreiben kann schon funktionieren, aber wenn dann "b=a+1" kommt ist b eventuell trotzdem 2 und nicht 3. Und das war nur ein einfaches Beispiel, sich so gegen die Regeln wehren kann buchstäblich alle möglichen Auswirkungen haben. Falsches Verhalten wie hier, oder Abstürze, oder teilweise kanns wie erwartet funktionieren, je nach Gerät kanns auch explodieren... usw.usw. . EInfach nicht machen
Warum nicht erlaubt Teil 2: Bei "normalen" Computern zwar kein Problem, aber es gibt auch Geräte, wo const-Variablen in einem speziellen Speicherteil sind, in den wirklich nicht so einfach geschrieben werden kann.
....
b) Das waren normale const int, jetzt const Pointer nur kurz:
Hier gibt es "drei" Sachen, die konst sein können:
Erstens, a:
C++:
const int a = 1;
int *p = &a;
Zweitens, die Adresse die in p gespeichert ist:
C++:
int a = 1;
const int *p = &a;
Drittens, das worauf p zeigt (nicht das Selbe wie Fall 1)
C++:
int a = 1;
int * const p = &a;
(oder auch mehrere, oder alle drei, const gleichzeitig)
Wenn a const ist, wie schon beschrieben, darf es nicht verändert werden (auch durch den Pointer nicht). Wenn p (Adresse) const ist kann es immer nur auf a zeigen, aber a kann beliebig geändert werden (egal ob durch p oder direkt).
Wenn p's Ziel const ist: p' Adresse kann verändert werden, es muss also nicht immer auf a zeigen. a kann auch verändert werden. Aber a kann nur direkt per "a=2" verändert werden, nicht durch p. (Bei dieser Variante gibts keine Probleme mit dem Optimierer usw. wenn man es umgehen will, a selber ist normal beschreibbar).
Was Ähnliches gilt auch für Referenzen, falls bekannt.
...
c) Funktionsparameter usw.
Ähnlich wie oben:
C++:
int plus1(const int x) { return x+1; }
int a = 1;
int b = plus1(a);
x in der Funktion darf nicht verändert werden, a außen selber aber schon.
Auch Returnwerte usw. ähnlich dazu
...
d) Noch etwas, was nicht ganz zu den vorigen Sachen passt
Funktionen von Klassen können const sein (die Funktion, keine Variable).
C++:
class abc
{
int d;
...
int f() const
{
d = 1;
}
};
f ist hier const, also darf es keine Membervariablen der Klasse (also hier d) verändern. "d=1" => Fehler. d selber ist änderbar, nur f darf es nicht.
.
...
.
So, genug dazu.
constexpr ist noch strenger als const: Wirklich nur Sachen, die zur Compilezeit bestimmt werden können, dürfen das sein. (Was schafft der Compiler? Es gibt ja mehrere verschiedene Compiler ... es gibt gewisse Mindestanforderungen, die von allen Compilern erwartet werden)
Für einfache Variablen bedeutet das:
C++:
constepxr int a = 1; //ok
constepxr int b = 1+1; //ok, das schafft der Compiler
constepxr int c = a; //a ist auch constexpr, daher kann c auch bestimmt werden
constepxr int d = eineFunktionDieVonDerTastaturEinliest(); //nicht erlaubt
int e = eineFunktionDieVonDerTastaturEinliest(); //ausnahmsweise ein normales ist...
constepxr int f = e; //nicht erlaubt weil e nicht constexpr ist
//usw.
Es gibt auch constexpr-Funktionen: Sie haben ziemlich strenge Beschränkungen, was für Code drin sein darf, um den Returnwert auch zur Compilezeit bestimmbar zu machen. Den Wert solcher Funktionen kann man dann auch constexpr-Variablen zuweisen (anders als den Wert der Tastatur-Einlese-Funktion, die die Anforderungen für constexpr nicht erfüllen kann. Bei der constepxr dazuschreiben führt nur zu Compilerfehlern)
Die Details sidn deutlich komplizierter, aber hier egal.
Was das bringt:
a) Noch bessere Optimierungen (zumindest manchmal)
b) Es gibt in C++-Code manchmal Stellen, wo eigentlich nur fixe Werte (keine Variablen, keine Funktionsreturnwerte, nichts) eingetragen werden dürfen (zB. Größen von einfachen statischen Arrays, Literal-Templateparameter, usw.). constexpr-Variablen dürfen dort auch verwendet werden.