Lass den Compiler den Typ wählen
Auf der vorherigen Seite hast du gesehen, dass jede C++-Variable einen festen Typ hat - int, double, std::string und so weiter. Diesen Typ von Hand auszuschreiben ist bei int count = 0; in Ordnung, wird aber unübersichtlich, sobald die Typen länger werden. Das Schlüsselwort auto (C++11 und später) lässt den Compiler den Typ aus dem zugewiesenen Wert ableiten, sodass du den Wert einmal schreibst und den Rest dem Compiler überlässt.
Die Kernidee: auto ist keine dynamische Typisierung. Jede Variable hat weiterhin einen konkreten Typ, der zur Übersetzungszeit festgelegt wird. auto erspart dir nur, ihn auszuschreiben.
Warum sich auto auszahlt
Bei kurzen, offensichtlichen Typen sind auto count = 0; und int count = 0; gleich gut lesbar. Wo sich auto wirklich auszahlt, sind lange, sich wiederholende Typnamen - die Art, die man von den Containern und Iteratoren der Standardbibliothek bekommt.
Vergleiche die ausführliche Version mit der auto-Version:
// Ohne auto - der Typ wird faktisch zweimal geschrieben
std::vector<std::pair<std::string, int>>::iterator it = scores.begin();
// Mit auto - der Compiler kennt den Typ bereits
auto it = scores.begin();
Beide deklarieren genau denselben Iteratortyp. Die zweite ist leichter zu lesen und gerät nicht aus dem Takt, wenn du scores später in einen anderen Container änderst.
Hier in einem vollständigen Programm:
auto in bereichsbasierten for-Schleifen
Der häufigste Ort, an dem dir auto begegnet, ist die bereichsbasierte for-Schleife. Du willst den Elementtyp fast nie von Hand ausschreiben, und wie du das auto schreibst, entscheidet, ob du eine Kopie oder eine Referenz bekommst.
Drei Varianten, die dir begegnen, und was jede bedeutet:
for (auto x : v)-xist eine Kopie jedes Elements. Günstig fürint, verschwenderisch für große Objekte.for (auto& x : v)-xist eine Referenz; du kannst die Elemente an Ort und Stelle ändern.for (const auto& x : v)-xist eine schreibgeschützte Referenz. Verwende sie, wenn du nur lesen musst.
Das nächste Programm verändert den Container über auto&:
Fallstrick: Schreibst du in dieser Schleife for (auto n : nums) (ohne &), würde n *= 10 stillschweigend nur die Kopie ändern und nums unangetastet lassen. Der Compiler warnt dich nicht - die Schleife tut einfach nichts Nützliches.
Was auto verwirft
Ein einfaches auto leitet den Typ genauso ab wie ein per Wert übergebener Funktionsparameter: Es verwirft das const der obersten Ebene, Referenzen und volatile. Das bedeutet, dass auto dir immer eine frische, veränderbare Kopie liefert, sofern du nichts anderes verlangst.
Wenn du das const behalten oder die Kopie vermeiden willst, fügst du die Qualifizierer selbst hinzu. Das Muster besteht darin, auto genauso zu schmücken, wie du jeden Typ schmücken würdest:
auto leitet also den Basistyp ab; &, const und * sind Stellschrauben, die du obendrauf setzt. auto ist der Typ, const auto& ist eine schreibgeschützte Referenz darauf.
Häufige Fehler und Fallstricke
auto nimmt dir den Tippaufwand ab, nicht die Notwendigkeit, Typen zu verstehen. Ein paar Fallen erwischen Anfänger:
Du musst initialisieren. auto hat aus einer leeren Deklaration nichts abzuleiten, daher ist dies ein harter Übersetzungsfehler:
auto x; // error: declaration of 'auto x' has no initializer
auto y = 0; // in Ordnung
Ganzzahlliterale sind int, nicht double. auto half = 1 / 2; leitet int ab und speichert 0, weil 1 / 2 eine Ganzzahldivision ist, bevor auto es überhaupt zu sehen bekommt. Der Typ folgt dem Wert:
auto verwirft die Referenz - achte auf Überraschungen mit hängenden Kopien. Wenn eine Funktion eine Referenz zurückgibt und du sie mit einfachem auto auffängst, bekommst du eine Kopie, was in einer heißen Schleife manchmal ein echter Performance-Bug ist (eine tiefe Kopie eines großen Objekts in jeder Iteration). Greife zu const auto&, wenn du „anschauen, nicht mitnehmen" meinst.
Verstecke den Typ nicht, wenn er wichtig ist. auto result = compute(); ist in Ordnung, wenn der Rückgabetyp von compute aus dem Kontext offensichtlich ist, aber wenn ein Leser erst suchen muss, was result tatsächlich ist, kann das Ausschreiben des Typs die freundlichere Wahl sein. auto dient dazu, Rauschen zu reduzieren, nicht dazu, die Absicht zu verbergen.
Weiter: Konstanten und const
Du hast nun gesehen, dass auto const bewusst verwirft, sofern du nicht darum bittest, es zu behalten - was die naheliegende Frage aufwirft: Was garantiert const eigentlich, und wann solltest du einen Wert überhaupt als unveränderlich markieren? Die nächste Seite gräbt sich in const, konstante Ausdrücke und warum „mach es standardmäßig const" eine der nützlichsten Gewohnheiten in C++ ist.
Häufig gestellte Fragen
Was macht das Schlüsselwort auto in C++?
auto weist den Compiler an, den Typ der Variablen aus ihrem Initialisierer abzuleiten. auto x = 5; macht x zu einem int; auto y = 3.14; macht y zu einem double. Der Typ wird zur Übersetzungszeit festgelegt - auto ist keine dynamische Typisierung, sondern eine Abkürzung, um den Typ nicht selbst hinschreiben zu müssen.
Behält auto const und Referenzen in C++ bei?
Nein. Ein einfaches auto verwirft das const der obersten Ebene, Referenzen und volatile. Wenn die Quelle const int& r ist, ergibt auto x = r; eine einfache int-Kopie. Um sie beizubehalten, schreibst du es explizit hin: Verwende const auto&, um eine schreibgeschützte Referenz ohne Kopie zu binden.
Kann man eine Variable mit auto deklarieren, ohne sie zu initialisieren?
Nein. auto x; ist ein Übersetzungsfehler, weil es keinen Initialisierer gibt, aus dem der Compiler einen Typ ableiten könnte. Jeder auto-Variablen muss am Punkt ihrer Deklaration ein Wert zugewiesen werden.