C ++ auto & vs auto

88

Czy podczas tworzenia zmiennych lokalnych należy używać (const) auto&lub auto?

na przykład:

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

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

Gdzie SomeMethod () zwraca wartość inną niż pierwotna - być może inny typ zdefiniowany przez użytkownika. Rozumiem, że const auto& resultjest to poprawne, ponieważ wynik zwracany przez SomeMethod () wywołałby konstruktor kopiujący dla zwróconego typu. Proszę, popraw mnie jeśli się mylę.

A co z typami prymitywnymi? Zakładam, że const auto sum = 1 + 2;ma rację.

Czy dotyczy to również zakresu opartego na pętlach?

for(const auto& object : objects)
rohunb
źródło
1
Gorąco polecam przeczytanie tego: safaribooksonline.com/library/view/effective-modern-c/ ... Pierwsze dwa rozdziały są bezpłatne i opisują dedukcję typu szablonu, co w zasadzie autodziała (z wyjątkiem osobliwego przypadku initializer_lists, które są niededukowane w kontekście szablonu), a następnie autowpisz deduction.
vsoftco,

Odpowiedzi:

102

autoi auto &&obejmują większość przypadków:

  • Użyj, autogdy potrzebujesz lokalnej kopii. To nigdy nie przyniesie odniesienia. Konstruktor kopiujący (lub przenoszący) musi istnieć, ale może nie zostać wywołany z powodu optymalizacji kopiowania .

  • Użyj, auto &&gdy nie obchodzi Cię, czy obiekt jest lokalny, czy nie. Technicznie rzecz biorąc, zawsze spowoduje to utworzenie referencji, ale jeśli inicjator jest tymczasowy (np. Funkcja zwraca wartość), będzie zachowywał się zasadniczo jak Twój własny obiekt lokalny.

    auto &&Nie gwarantuje również, że obiekt będzie można modyfikować. Biorąc pod uwagę constprzedmiot lub odniesienie, wywnioskuje const. Jednak często zakłada się modyfikowalność, biorąc pod uwagę specyficzny kontekst.

auto &i auto const &są trochę bardziej szczegółowe:

  • auto &gwarantuje, że udostępniasz zmienną czemuś innemu. Jest to zawsze odniesienie, a nigdy tymczasowe.

  • auto const &jest podobny auto &&, ale zapewnia dostęp tylko do odczytu.

A co z typami pierwotnymi / innymi niż pierwotne?

Nie ma różnicy.

Czy dotyczy to również zakresu opartego na pętlach?

Tak. Stosując powyższe zasady,

  • Służy auto &&do modyfikowania i odrzucania wartości sekwencji w pętli. (To znaczy, chyba że kontener zapewnia widok tylko do odczytu, na przykład std::initializer_listw takim przypadku będzie to faktycznie auto const &.)
  • Służy auto &do modyfikowania wartości sekwencji w znaczący sposób.
  • Użyj, auto const &aby uzyskać dostęp tylko do odczytu.
  • Służy autodo pracy z kopiami (modyfikowalnymi).

Wspominasz również auto constbez odniesienia. To działa, ale nie jest zbyt często używane, ponieważ rzadko istnieje korzyść z dostępu tylko do odczytu do czegoś, co już posiadasz.

Potatoswatter
źródło
Sutter mówi, że auto & śledzi konstencję
Jesse Pepper
1
@JessePepper Yes. (Jednak odwoływanie się do autorytetów jest trochę dziwne.) Czy odnosisz się do jakiejś konkretnej części tego?
Potatoswatter
W gruncie rzeczy auto&wydaje się być dobrym wyborem. Ale używaj, const auto&gdy chcesz dodać stałość, której jeszcze nie ma. auto&&służy do przekazywania, co moim zdaniem zdarza się częściej niż myśli Sutter. Na przykład, możesz chcieć zapisać wartość zwracaną przez, auto&&a następnie „przekazać” ją do dwóch rzeczy, takich jak std :: cout, aby zobaczyć wartość do debugowania, a także przekazać ją do innej funkcji. Kiedyś częściej używałem auto &&, ale zostałem ugryziony raz lub dwa razy, gdy zrobił kilka nieoczekiwanych rzeczy. Żałuję, że nie zwróciłem większej uwagi na to, co poszło nie tak!
Jesse Pepper
@JessePepper Tak, auto&&jest powiązany z brakującą funkcją językową, która powinna pozwolić na podzielenie dowolnego oświadczenia na mniejsze. Brakującą częścią jest przedłużenie żywotności… Włożyłem sporo wysiłku w naprawienie tego, ale nikt tego nie zauważył. Nie wkładaj zbyt wiele w punditry :)
Potatoswatter
On auto const: bardziej naturalne może być zapisanie auto const x = fn (); jeśli wiesz, że funkcja nie zwraca referencji i chcesz, aby obiekt x nie zmieniał się, aby uniknąć błędów lub dokument, że jest używany w zakresie. W ten sam sposób, w jaki normalnie byś nie napisał: const int & x = 1; Ale auto const & daje równoważne wyniki ze względu na reguły przedłużania czasu życia dla zadeklarowanych w ten sposób odwołań.
Spacen Jasset
47

Tak, poprawne jest użycie autoi auto&dla zmiennych lokalnych. Podczas uzyskiwania zwracanego typu funkcji również poprawne jest użycie auto&. Dotyczy to również zakresu opartego na pętlach.

Ogólne zasady użytkowania autoto:

  • Wybierz, auto xkiedy chcesz pracować z kopiami.
  • Wybierz, auto &xkiedy chcesz pracować z oryginalnymi elementami i możesz je modyfikować.
  • Wybierz, auto const &xkiedy chcesz pracować z oryginalnymi elementami i nie modyfikuj ich.

Więcej informacji na temat specyfikacji automatycznej można znaleźć tutaj .

Fantom
źródło
9

autoużywa tego samego mechanizmu dedukcji typu co szablony, z jedynym wyjątkiem, o którym wiem, że jest to lista inicjująca nawiasy klamrowe, które są wywnioskowane przez autoas std::initializer_list, ale nie są wywnioskowane w kontekście szablonu.

auto x = expression;

działa najpierw usuwając wszystkie kwalifikatory odwołania i cv z typu wyrażenia po prawej stronie, a następnie dopasowując typ. Na przykład, jeśli masz const int& f(){...}to auto x = f();dedukuje xjako int, a nie const int& .

Druga forma,

auto& x = expression

nie usuwa kwalifikatorów cv, więc korzystając z powyższego przykładu, auto& x = f()wnioskuje xjako const int&. Pozostałe kombinacje po prostu dodają kwalifikatory cv.

Jeśli chcesz, aby typ był zawsze wywnioskowany za pomocą kwalifikatorów cv-ref, użyj niesławnego decltype(auto)w C ++ 14, który używa decltypereguł odliczania typów.

Więc w skrócie, jeśli chcesz kopiować, użyj auto, jeśli chcesz odniesienia, użyj auto&. Używaj constzawsze, gdy chcesz mieć więcej const.


EDYTUJ Istnieje dodatkowy przypadek użycia,

auto&& x = expression;

który wykorzystuje reguły zwijania referencji, takie same jak w przypadku przekazywania odwołań w kodzie szablonu. Jeśli expressionjest lwartością, to xjest odwołaniem do lwartości z kwalifikatorami cv expression. Jeśli expressionjest wartością r, to xjest odniesieniem do wartości r.

vsoftco
źródło
@Potatoswatter Dzięki, zredagowano. Właściwie to zastanawiam się nad CV dla rvalues. Czy istnieje prosty sposób testowania? Jak możesz mieć rvalue kwalifikowaną do CV? Po powrocie funkcji cv jest odrzucane.
vsoftco,
Nie, nie jest odrzucany przy powrocie funkcji. Jest odrzucany dla wartości prvalues ​​wszystkich typów skalarnych (C ++ 14 [i inne wydania] §5 / 6). Możesz go uzyskać za pomocą wywołania funkcji lub notacji rzutowanej. Wartości x kwalifikowane jako CV działają tak samo, jak wszystko inne: auto && x = std::move< const int >( 5 );zadeklarują int const && x, chociaż są rzadko używane.
Potatoswatter
@Potatoswatter dzięki, masz rację, mój błąd. Najpierw przetestowałem z POD, w którym to przypadku cv jest odrzucane i pomyślałem, że to ogólny przypadek. Oczywiście nie należy tego odrzucać, ponieważ generalnie można chcieć zachować cv (np. Aby nie można było wywoływać funkcji składowej innej niż stała przy zwracaniu wartości r).
vsoftco,
Odrzucone dla typów skalarnych. POD mogą być klasami. W każdym razie jest to hackerski róg przecięcia modelu wyrażenia i modelu obiektowego.
Potatoswatter
2

Czy podczas tworzenia zmiennych lokalnych należy używać (const) auto & czy auto?

Tak. Auto to nic innego jak typ wywodzący się z kompilatora, więc używaj odwołań tam, gdzie normalnie używasz referencji, oraz lokalnych (automatycznych) kopii, w których normalnie używasz kopii lokalnych. To, czy użyć odwołania, czy nie, jest niezależne od dedukcji typu.

Gdzie SomeMethod () zwraca wartość inną niż pierwotna - być może inny typ zdefiniowany przez użytkownika. Rozumiem, że const auto & result jest poprawne, ponieważ wynik zwracany przez SomeMethod () wywołałby konstruktor kopiujący dla zwróconego typu. Proszę, popraw mnie jeśli się mylę.

Prawny? Tak, z konst. Najlepsze praktyki? Prawdopodobnie nie, nie. Przynajmniej nie w C ++ 11. Zwłaszcza jeśli wartość zwrócona przez SomeMethod () jest już tymczasowa. Będziesz chciał dowiedzieć się więcej o semantyce przenoszenia w C ++ 11, elizji kopiowania i optymalizacji wartości zwracanej: https://juanchopanzacpp.wordpress.com/2014/05/11/want-speed-dont-always-pass-by- wartość/

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

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

A co z typami prymitywnymi? Zakładam, że const auto sum = 1 + 2; jest poprawne.

Tak, w porządku.

Czy dotyczy to również zakresu opartego na pętlach?

for (const auto & object: objects)

Tak, to też jest w porządku. Cały czas piszę taki kod w pracy.

tweej
źródło