Suche…
Bemerkungen
Das Schlüsselwort auto
ist ein Typname, der einen automatisch abgeleiteten Typ darstellt.
Es war bereits ein reserviertes Schlüsselwort in C ++ 98, das von C geerbt wurde. In alten Versionen von C ++ konnte explizit angegeben werden, dass eine Variable eine automatische Speicherdauer hat:
int main()
{
auto int i = 5; // removing auto has no effect
}
Diese alte Bedeutung ist jetzt entfernt.
Grundlegende Auto-Probe
Das Schlüsselwort auto
bietet die automatische Ableitung des Typs einer Variablen.
Dies ist besonders praktisch, wenn Sie lange Typnamen verwenden:
std::map< std::string, std::shared_ptr< Widget > > table;
// C++98
std::map< std::string, std::shared_ptr< Widget > >::iterator i = table.find( "42" );
// C++11/14/17
auto j = table.find( "42" );
mit bereichsbasierter für Schleifen :
vector<int> v = {0, 1, 2, 3, 4, 5};
for(auto n: v)
std::cout << n << ' ';
mit lambdas :
auto f = [](){ std::cout << "lambda\n"; };
f();
um die Wiederholung des Typs zu vermeiden:
auto w = std::make_shared< Widget >();
um überraschende und unnötige Kopien zu vermeiden:
auto myMap = std::map<int,float>();
myMap.emplace(1,3.14);
std::pair<int,float> const& firstPair2 = *myMap.begin(); // copy!
auto const& firstPair = *myMap.begin(); // no copy!
Der Grund für die Kopie ist, dass der zurückgegebene Typ tatsächlich std::pair<const int,float>
!
Auto- und Ausdrucksvorlagen
auto
kann auch Probleme verursachen, wenn Ausdrucksvorlagen ins Spiel kommen:
auto mult(int c) {
return c * std::valarray<int>{1};
}
auto v = mult(3);
std::cout << v[0]; // some value that could be, but almost certainly is not, 3.
Der Grund ist, dass operator*
on valarray
Ihnen ein Proxy-Objekt gibt, das sich auf das valarray
bezieht, um eine valarray
Bewertung valarray
. Wenn Sie auto
, erstellen Sie eine baumelnde Referenz. Statt mult
hatte std::valarray<int>
, dann würde der Code definitiv 3 drucken.
auto, const und referenzen
Das auto
Schlüsselwort selbst repräsentiert einen Werttyp, ähnlich wie int
oder char
. Sie kann mit dem Schlüsselwort const
und dem Symbol &
geändert werden, um einen konstanten Typ oder einen Referenztyp darzustellen. Diese Modifikatoren können kombiniert werden.
In diesem Beispiel ist s
ein Wertetyp (sein Typ wird als std::string
), sodass jede Iteration der for
Schleife einen String aus dem Vektor in s
kopiert .
std::vector<std::string> strings = { "stuff", "things", "misc" };
for(auto s : strings) {
std::cout << s << std::endl;
}
Wenn der Hauptteil der Schleife s
ändert (z. B. durch Aufrufen von s.append(" and stuff")
), wird nur diese Kopie geändert, nicht das ursprüngliche s.append(" and stuff")
von strings
.
Wenn s
jedoch mit auto&
deklariert ist, ist es ein Referenztyp (wird als std::string&
), so dass ihm bei jeder Wiederholung der Schleife eine Referenz auf einen String im Vektor zugewiesen wird:
for(auto& s : strings) {
std::cout << s << std::endl;
}
Im Hauptteil dieser Schleife wirken sich Änderungen an s
direkt auf das Element der strings
, auf die es verweist.
Wenn s
als const auto&
deklariert ist, ist es schließlich ein const-Referenztyp. Dies bedeutet, dass ihm bei jeder Iteration der Schleife ein const-Referenzwert für einen String im Vektor zugewiesen wird:
for(const auto& s : strings) {
std::cout << s << std::endl;
}
Innerhalb dieser Schleife können s
nicht geändert werden (dh es können keine Nicht-Konstanten-Methoden aufgerufen werden).
Wenn Sie auto
mit bereichsbasierten for
Schleifen verwenden, ist es im Allgemeinen ratsam, const auto&
wenn der Schleifenrumpf die überlaufene Struktur nicht ändert, da dadurch unnötige Kopien vermieden werden.
Hinterlegter Rückgabetyp
auto
wird in der Syntax für abschließende Rückgabetypen verwendet:
auto main() -> int {}
das ist äquivalent zu
int main() {}
Meistens nützlich in Verbindung mit decltype
, um Parameter anstelle von std::declval<T>
:
template <typename T1, typename T2>
auto Add(const T1& lhs, const T2& rhs) -> decltype(lhs + rhs) { return lhs + rhs; }
Generisches Lambda (C ++ 14)
C ++ 14 erlaubt die Verwendung von auto
in Lambda-Argumenten
auto print = [](const auto& arg) { std::cout << arg << std::endl; };
print(42);
print("hello world");
Das Lambda entspricht meistens
struct lambda {
template <typename T>
auto operator ()(const T& arg) const {
std::cout << arg << std::endl;
}
};
und dann
lambda print;
print(42);
print("hello world");
Auto- und Proxy-Objekte
Manchmal verhält sich auto
möglicherweise nicht ganz so, wie es von einem Programmierer erwartet wurde. Der Typ leitet den Ausdruck ab, auch wenn der Typabzug nicht richtig ist.
Wenn zum Beispiel Proxy-Objekte im Code verwendet werden:
std::vector<bool> flags{true, true, false};
auto flag = flags[0];
flags.push_back(true);
Hier flag
würde nicht bool
, aber std::vector<bool>::reference
, da für bool
Spezialisierung von Template - vector
des operator []
gibt ein Proxy - Objekt mit Konvertierungsoperator operator bool
definiert.
Wenn flags.push_back(true)
den Container ändert, kann diese Pseudo-Referenz enden und sich auf ein Element beziehen, das nicht mehr vorhanden ist.
Es macht auch die nächste Situation möglich:
void foo(bool b);
std::vector<bool> getFlags();
auto flag = getFlags()[5];
foo(flag);
Der vector
wird sofort gelöscht. flag
ist also eine Pseudo-Referenz auf ein Element, das gelöscht wurde. Der Aufruf von foo
ruft ein undefiniertes Verhalten auf.
In solchen Fällen können Sie eine Variable mit auto
deklarieren und initialisieren, indem Sie den Typ ausführen, den Sie ableiten möchten:
auto flag = static_cast<bool>(getFlags()[5]);
an diesem Punkt ist es jedoch sinnvoller, auto
durch bool
ersetzen.
Ein weiterer Fall, in dem Proxy-Objekte Probleme verursachen können, sind Ausdrucksvorlagen . In diesem Fall sind die Vorlagen manchmal nicht so ausgelegt, dass sie aus Effizienzgründen über den aktuellen Vollausdruck hinausgehen. Die Verwendung des Proxy-Objekts beim nächsten bewirkt ein undefiniertes Verhalten.