Dieses AUTO ist cool (Teil 2)
« | 08 Sep 2019 | »Wir wissen nun, dass Großvater C
sein auto
nie benutzt hat und es in der Garage verrosten ließ.
Doch sein Enkel C++ 11, ein bekennender
auto
-Freak, zerlegte die Karosserie, entfernte die Spuren des Zahns der Zeit
und baute sich daraus einen neuen Boliden, der jedoch bald ein Eigenleben
entwickelte.
Dieser wurde zu einer Rennsau, die bei fast jedem Wettrennen als Nummer 1
über die Ziellinie sauste
… vorausgesetzt: Es saß der richtige Fahrer hinterm Lenkrad.
Wenn man unter C++ weiter “klassisch” programmiert, könnte man denken, dass man
auto
nicht braucht.
Es ist sogar übersichtlicher, wenn man Datentypen selbst ausschreibt
(int x = 42;
) anstatt alles von auto
erledigen zu lassen (auto x = 42;
).
Doch spätestens, wenn man mit Templates
und Spezialisierungen arbeitet, sind Typen bei der Deklaration nicht mehr
zwingend vorhersehbar.
Doch der Compiler weiß bei der Instanziierung ganz genau, mit welchen Typen
er arbeitet, und genau hier wird auto
zum gefeierten Heilsbringer.
1template<class T> struct next_greater_type 2{ 3 typedef long double type_t; /* finally the "greatest" type */ 4}; 5 6template<> struct next_greater_type<char> 7{ 8 typedef short type_t; 9}; 10 11template<> struct next_greater_type<short> 12{ 13 typedef long type_t; 14}; 15 16template<> struct next_greater_type<long> 17{ 18 typedef long long type_t; 19}; 20 21template<> struct next_greater_type<long long> 22{ 23 typedef double type_t; 24}; 25 26 27template<class T> 28typename next_greater_type<T>::type_t multiply(T const& t1, int t2) 29{ 30 typedef typename next_greater_type<T>::type_t greater_type_t; 31 32 greater_type_t a = greater_type_t(t1); 33 greater_type_t b = greater_type_t(t2); 34 35 greater_type_t c = a * b; 36 return c; 37} 38 39int main() 40{ 41 char c = 127; 42 short s = 32767; 43 long l = 2147483647L; 44 long long ll = 9223372036854775807LL; 45 46 auto result1 = multiply(c, 4); // short result 47 auto result2 = multiply(s, 4); // long result 48 auto result3 = multiply(l, 4); // long long result 49 auto result4 = multiply(ll, 4); // double result 50 51 return 0; 52}
Im Beispiel wird für jeden Zahlentypen der nächst größere festgelegt. Die generische “Multiplikation” soll so einen Ausgabetypen festlegen, der ohne Verlust das Ergebnis enthalten kann.
Zugegeben, das Beispiel ist wirklich sehr exemplarisch und wenig praxisnah.
Aber es zeigt, dass auto
einem den Aufwand abnimmt, stets über den
template
typedef
den Ergebnistypen selbst zu bestimmen.
auto
und R-Value Referenzen
Seine größte Stärke spielt auto
meines Erachtens mit auto&&
aus.
Denn wir Programmierer machen gerne den Fehler durch ungenaue und schlecht passende Datentypenangaben Optimierungen zu verhindern.
Gibt eine Funktion eine const-Referenz zurück, sollte diese auch genau so entgegengenommen werden. Nimmt man sie als neue Instanz an, entsteht eine (oft sinnlose) Kopie, die Speicher und CPU-Zeit frisst.
Genau hier hilft uns auto&&
, denn dieses Konstrukt garantiert, dass die
Variable den perfekten Typen erhält.
1std::string get_copy(); 2std::string& get_reference(); 3std::string const& get_const_reference(); 4std::string&& get_rv_reference(); 5 6void lame_foo() 7{ 8 auto a = get_copy(); // std::string / copy 9 auto b = get_reference(); // std::string / copy 10 auto c = get_const_reference(); // std::string / copy 11 auto d = get_rv_reference(); // std::string / move 12} 13void smart_foo() 14{ 15 auto&& a = get_copy(); // std::string&& 16 auto&& b = get_reference(); // std::string& 17 auto&& c = get_const_reference(); // std::string const& 18 auto&& d = get_rv_reference(); // std::string&& 19}
In lame_foo
löst auto
stets einen std::string aus, was mit
Ausnahme der letzten Zeile immer ein Kopieren des Strings erfordert.
smart_foo
hingegen nutzt std::string&&
um Kopien durch
Move-Konstruktion
abzufangen und im Fall von “gewöhnlichen” Referenzen werden diese erkannt und
als eben solche ohne Performanceverlust entgegengenommen.
Und das ist kurz gesagt: Perfekt.
Scott Meyers bezeichnet diese Nutzung von Referenzen übrigens gerne als Universal References.
Fazit
auto
zählt im modernen C++ ganz klar zu meinen Favoriten.
Mehr kann man dazu gar nicht sagen.
Mein Problem in der Entwicklung ist allerdings, dass ich aus Rücksicht auf ältere Compiler (z.B. für Windows CE ), immer noch oft auf dieses Feature verzichte.
Doch bei neuen Projekten ist auto
absolut Pflicht!