C ++ auto & vs auto

88

Ist es richtig, beim Erstellen lokaler Variablen (const) auto&oder zu verwenden auto?

z.B:

SomeClass object;
const auto result = object.SomeMethod();

oder const auto& result = object.SomeMethod();

Wobei SomeMethod () einen nicht primitiven Wert zurückgibt - möglicherweise einen anderen benutzerdefinierten Typ. const auto& resultNach meinem Verständnis ist dies korrekt, da das von SomeMethod () zurückgegebene Ergebnis den Kopierkonstruktor für den zurückgegebenen Typ aufrufen würde. Bitte korrigieren Sie mich, wenn ich falsch liege.

Was ist mit primitiven Typen? Ich nehme an, const auto sum = 1 + 2;ist richtig.

Gilt dies auch für Bereiche, die auf Schleifen basieren?

for(const auto& object : objects)
Rohunb
quelle
1
Ich empfehle Ihnen dringend, dies zu lesen: safaribooksonline.com/library/view/effective-modern-c/… Die ersten beiden Kapitel sind kostenlos und beschreiben den Abzug von Vorlagentypen. Dies funktioniert im Wesentlichen so auto(mit Ausnahme des besonderen Falls von initializer_lists) nicht in einem Vorlagenkontext abgeleitet), geben Sie dann autoAbzug ein.
vsoftco

Antworten:

102

autound auto &&decken die meisten Fälle ab:

  • Verwenden autoSie diese Option, wenn Sie eine lokale Kopie benötigen. Dies wird niemals eine Referenz erzeugen. Der Kopierkonstruktor (oder Verschiebungskonstruktor) muss vorhanden sein, wird jedoch aufgrund der Optimierung der Kopierelision möglicherweise nicht aufgerufen .

  • Verwenden auto &&Sie diese Option, wenn es Ihnen egal ist, ob das Objekt lokal ist oder nicht. Technisch gesehen erzeugt dies immer eine Referenz, aber wenn der Initialisierer ein temporärer ist (z. B. die Funktion wird nach Wert zurückgegeben), verhält er sich im Wesentlichen wie Ihr eigenes lokales Objekt.

    Außerdem auto &&garantiert nicht , dass das Objekt veränderbar sein wird, auch nicht . Wenn ein constObjekt oder eine Referenz gegeben ist, wird daraus abgeleitet const. In Anbetracht des spezifischen Kontexts wird jedoch häufig von einer Modifizierbarkeit ausgegangen.

auto &und auto const &sind etwas spezifischer:

  • auto &garantiert, dass Sie die Variable mit etwas anderem teilen. Es ist immer ein Hinweis und niemals auf eine vorübergehende.

  • auto const &ist wie auto &&, bietet aber schreibgeschützten Zugriff.

Was ist mit primitiven / nicht-primitiven Typen?

Es gibt keinen Unterschied.

Gilt dies auch für Bereiche, die auf Schleifen basieren?

Ja. Anwendung der oben genannten Grundsätze,

  • Verwenden Sie auto &&diese Option, um Werte der Sequenz innerhalb der Schleife zu ändern und zu verwerfen. (Das heißt, es sei denn, der Container bietet eine schreibgeschützte Ansicht, z. B. std::initializer_listin diesem Fall handelt es sich tatsächlich um eine auto const &.)
  • Verwenden Sie auto &diese Option, um die Werte der Sequenz auf sinnvolle Weise zu ändern.
  • Verwenden Sie auto const &für Nur - Lese-Zugriff.
  • Verwenden Sie autodiese Option , um mit (veränderbaren) Kopien zu arbeiten.

Sie erwähnen auch auto constohne Referenz. Dies funktioniert, wird jedoch nicht häufig verwendet, da der schreibgeschützte Zugriff auf etwas, das Sie bereits besitzen, selten von Vorteil ist.

Kartoffelklatsche
quelle
Sutter sagt, dass Auto & verfolgt Konstanz
Jesse Pepper
1
@ JessePepper Ja. (Es ist allerdings etwas seltsam, sich an die Autorität zu wenden.) Beziehen Sie sich auf einen bestimmten Teil davon?
Potatoswatter
Im Wesentlichen auto&scheint eine gute Wahl zu sein. Verwenden const auto&Sie diese Option jedoch, wenn Sie Konstanz hinzufügen möchten, die noch nicht vorhanden ist. auto&&ist für die Weiterleitung, was meiner Meinung nach häufiger vorkommt als Sutter denkt. Beispielsweise möchten Sie möglicherweise einen Rückgabewert von speichern auto&&und ihn dann an zwei Dinge "weiterleiten", z. B. std :: cout, um den Wert für das Debuggen anzuzeigen und ihn auch an eine andere Funktion zu übergeben. Ich habe Auto && öfter benutzt, wurde aber ein- oder zweimal von ihm gebissen, als es einige unerwartete Dinge tat. Ich wünschte, ich hätte mehr beachtet, was schief gelaufen ist!
Jesse Pepper
@JessePepper Ja, auto&&ist ein fehlendes Sprachfeature verwendet, das sollte jeder Aussage erlaubt in kleinere Aussagen geteilt werden. Der fehlende Teil ist die Verlängerung der Lebensdauer… Ich habe mich sehr bemüht, dies zu beheben, aber niemand hat es bemerkt. Legen Sie nicht zu viel Wert auf Panditerie :)
Potatoswatter
Bei automatischer Konstante: Es kann natürlicher sein, automatische Konstante zu schreiben. X = fn (); Wenn Sie wissen, dass die Funktion keine Referenz zurückgibt und Sie möchten, dass sich das Objekt x nicht ändert, um Fehler zu vermeiden oder seine Verwendung im Bereich zu dokumentieren. Auf die gleiche Weise würden Sie normalerweise nicht schreiben: const int & x = 1; Auto const & liefert jedoch aufgrund der Regeln zur Verlängerung der Lebensdauer für auf diese Weise deklarierte Referenzen gleichwertige Ergebnisse.
Spacen Jasset
47

Ja, es ist richtig zu verwenden autound auto&für lokale Variablen. Wenn Sie den Rückgabetyp einer Funktion erhalten, ist die Verwendung ebenfalls korrekt auto&. Dies gilt auch für Bereiche, die auf Schleifen basieren.

Allgemeine Regeln für die Verwendung autosind:

  • Wählen Sie aus, auto xwann Sie mit Kopien arbeiten möchten.
  • Wählen Sie aus, auto &xwann Sie mit Originalelementen arbeiten möchten, und ändern Sie diese möglicherweise.
  • Wählen Sie aus, auto const &xwann Sie mit Originalelementen arbeiten möchten und diese nicht ändern möchten.

Weitere Informationen zum automatischen Spezifizierer finden Sie hier .

Phantom
quelle
9

autoverwendet den gleichen Mechanismus der Typableitung wie Vorlagen. Die einzige mir bekannte Ausnahme sind Klammer-Init-Listen, die von autoas abgeleitet std::initializer_list, aber in einem Vorlagenkontext nicht abgeleitet werden.

auto x = expression;

funktioniert, indem zuerst alle Referenz- und Lebenslaufqualifizierer vom Typ des Ausdrucks auf der rechten Seite entfernt und dann mit dem Typ abgeglichen werden. Zum Beispiel, wenn Sie const int& f(){...}dann auto x = f();folgert xwie int, und nicht const int& .

Die andere Form,

auto& x = expression

nicht abzustreifen die cv-Qualifizierer, also vor dem Beispiel verwendet wird , auto& x = f()folgert xwie const int&. Die anderen Kombinationen fügen nur Lebenslaufqualifizierer hinzu.

Wenn Sie möchten, dass Ihr Typ immer mit cv-ref-Qualifizierern abgeleitet wird, verwenden Sie das berüchtigte decltype(auto)in C ++ 14, das die decltypeTypabzugsregeln verwendet.

Kurz gesagt, wenn Sie Kopien möchten, verwenden Sie auto, wenn Sie Referenzen möchten, verwenden Sie auto&. Verwenden constSie, wann immer Sie zusätzliche const-ness wünschen .


BEARBEITEN Es gibt einen zusätzlichen Anwendungsfall,

auto&& x = expression;

Dabei werden die Regeln zum Reduzieren von Referenzen verwendet, wie im Fall der Weiterleitung von Referenzen im Vorlagencode. Wenn expressiones sich um einen Wert handelt, xhandelt es sich um eine Wertreferenz mit den Lebenslaufqualifizierern von expression. Wenn expressiones sich um einen rWert handelt, xhandelt es sich um eine rWert-Referenz.

vsoftco
quelle
@ Potatoswatter Danke, bearbeitet. Ich wundere mich eigentlich über den Lebenslauf für rvalues. Gibt es eine einfache Möglichkeit zum Testen? Und wie können Sie einen Lebenslauf-qualifizierten Wert haben? Bei Funktionsrückgabe wird cv verworfen.
vsoftco
Nein, es wird bei Funktionsrückgaben nicht verworfen. Es wird für Werte aller Skalartypen verworfen (C ++ 14 [und andere Editionen] §5 / 6). Sie können eine mit einem Funktionsaufruf oder einer Cast-Notation erhalten. Lebenslaufqualifizierte x-Werte funktionieren genauso wie alles andere: auto && x = std::move< const int >( 5 );werden deklariert int const && x, obwohl sie selten verwendet werden.
Potatoswatter
@ Potatoswatter danke, du hast recht, mein Fehler. Ich habe zuerst mit PODs getestet. In diesem Fall wird der Lebenslauf verworfen und dachte, dass dies der allgemeine Fall ist. Natürlich sollte es nicht verworfen werden, da man im Allgemeinen den Lebenslauf beibehalten möchte (z. B. kann man bei rvalue-Rückgaben keine Nicht-Konstanten-Member-Funktion aufrufen).
vsoftco
Für Skalartypen verworfen. PODs können Klassen sein. Wie auch immer, es ist eine hackige Ecke des Schnittpunkts des Ausdrucksmodells und des Objektmodells.
Potatoswatter
2

Ist es beim Erstellen lokaler Variablen richtig, (const) auto & oder auto zu verwenden?

Ja. Das Auto ist nichts anderes als ein vom Compiler abgeleiteter Typ. Verwenden Sie daher Referenzen, bei denen Sie normalerweise Referenzen verwenden würden, und lokale (automatische) Kopien, bei denen Sie normalerweise lokale Kopien verwenden würden. Ob eine Referenz verwendet werden soll oder nicht, ist unabhängig vom Typabzug.

Wobei SomeMethod () einen nicht primitiven Wert zurückgibt - möglicherweise einen anderen benutzerdefinierten Typ. Nach meinem Verständnis ist const auto & result korrekt, da das von SomeMethod () zurückgegebene Ergebnis den Kopierkonstruktor für den zurückgegebenen Typ aufrufen würde. Bitte korrigieren Sie mich, wenn ich falsch liege.

Legal? Ja, mit der const. Beste Übung? Wahrscheinlich nicht, nein. Zumindest nicht mit C ++ 11. Insbesondere nicht, wenn der von SomeMethod () zurückgegebene Wert bereits temporär ist. Sie möchten mehr über die C ++ 11-Verschiebungssemantik, die Kopierelision und die Optimierung von Rückgabewerten erfahren: https://juanchopanzacpp.wordpress.com/2014/05/11/want-speed-dont-always-pass-by- Wert/

http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=199

https://isocpp.org/wiki/faq/ctors#return-by-value-optimization

Was ist mit primitiven Typen? Ich nehme const auto sum = 1 + 2 an; ist richtig.

Ja, das ist in Ordnung.

Gilt dies auch für Bereiche, die auf Schleifen basieren?

für (const auto & object: Objekte)

Ja, das ist auch gut so. Ich schreibe diese Art von Code die ganze Zeit bei der Arbeit.

tweej
quelle