Używam nowego auto
słowa kluczowego dostępnego w standardzie C ++ 11 do skomplikowanych typów szablonów, do czego, moim zdaniem, został zaprojektowany. Ale używam go również do takich rzeczy jak:
auto foo = std::make_shared<Foo>();
I bardziej sceptycznie dla:
auto foo = bla(); // where bla() return a shared_ptr<Foo>
Nie widziałem wiele dyskusji na ten temat. Wydaje się, że auto
można to nadużyć, ponieważ typ jest często formą dokumentacji i kontroli poczytalności. Gdzie rysujesz linię w użyciu auto
i jakie są zalecane przypadki użycia tej nowej funkcji?
Aby wyjaśnić: nie proszę o filozoficzną opinię; Proszę o zamierzone użycie tego słowa kluczowego przez standardowy komitet, ewentualnie z komentarzami na temat tego, jak zamierzone użycie jest realizowane w praktyce.
Uwaga dodatkowa: To pytanie zostało przeniesione do SE.Programmers, a następnie z powrotem do Stack Overflow. Dyskusję na ten temat można znaleźć w tym meta pytaniu .
auto
słowa kluczowego, to wiesz, jak to miało być użyte. O to pytam, jako że ktoś, kto jest nowicjuszem w tej funkcji, jak mam jej używać?var
(to znaczy, gdy ludzie wpadli na pomysł, że to wcale nie było dynamiczne pisanie). Jeśli chcesz, możesz zacząć od tego pytania i przejść do powiązanych pytań.auto foo = bla();
„złym” jest wyraźnie opinią, a nie faktem, co powoduje, że pytanie to jest odpowiedzią na dyskusję, co czyni go istotnym dla Programistów SE, co dokładnie wskazują na to bliskie głosy. / wzruszenie ramionamiOdpowiedzi:
Myślę, że należy używać
auto
słowa kluczowego, ilekroć trudno jest napisać ten typ od pierwszego wejrzenia, ale typ prawej strony wyrażenia jest oczywisty. Na przykład za pomocą:aby uzyskać klucz złożony
boost::multi_index
, nawet jeśli wiesz, że takint
. Nie możesz po prostu pisać,int
ponieważ można to zmienić w przyszłości.auto
W tym przypadku napisałbym .Więc jeśli
auto
słowo kluczowe poprawia czytelność w konkretnym przypadku, użyj go. Możesz pisać,auto
gdy czytelnik jest oczywisty, jaki typauto
reprezentuje.Oto kilka przykładów:
źródło
bla()
dajeszfoo
.Używaj
auto
wszędzie, gdzie możesz - szczególnie,const auto
aby skutki uboczne nie były mniej niepokojące. Nie będziesz musiał martwić się typami, z wyjątkiem oczywistych przypadków, ale nadal będą dla ciebie weryfikowane statycznie i możesz uniknąć powtórzeń. Tam, gdzieauto
nie jest to możliwe, możesz używać wyrażeńdecltype
semantycznych jako kontraktów opartych na wyrażeniach. Twój kod będzie wyglądał inaczej, ale będzie pozytywną zmianą.źródło
auto&&
w złożonych sytuacjach edmundv.home.xs4all.nl/blog/2014/01/28/…const auto&
lubconst auto
chyba że wyraźnie chcą zmutować lub przenieść.auto str = std::string();
zamiaststd::string str;
?Łatwo. Użyj go, jeśli nie obchodzi Cię , jaki jest typ. Na przykład
Chodzi mi tylko o to,
i
co jest w pojemniku.To trochę jak typedefs.
Tutaj nie dbam o to, czy
h
iw
są zmiennoprzecinkowe, czy podwajające się, tylko, że są dowolnego rodzaju odpowiedniego do wyrażania wysokości i ciężarów .Lub zastanów się
Tutaj zależy mi tylko na tym, aby był to odpowiedni iterator
operator++()
, który w pewnym sensie przypomina pisanie kaczek.Nie można także przeliterować rodzaju lambd, więc
auto f = []...
jest to dobry styl. Alternatywą jest casting do,std::function
ale wiąże się to z narzutem.Nie mogę sobie wyobrazić „nadużycia”
auto
. Najbliższe, jakie mogę sobie wyobrazić, to pozbawienie się wyraźnej konwersji na jakiś znaczący typ - ale nie użyłbyśauto
do tego, zbudowałbyś obiekt pożądanego typu.Jeśli można usunąć niektóre redundancję w kodzie bez wprowadzania skutki uboczne, to musi być dobry, aby to zrobić.
Kontrprzykłady (zapożyczone z czyichś odpowiedzi):
Tutaj dbamy o to, jaki jest typ, więc powinniśmy pisać
Someclass i;
ifor(unsigned x = y;...
źródło
auto
.Idź po to. Używaj
auto
wszędzie tam, gdzie ułatwia pisanie kodu.Każda nowa funkcja w dowolnym języku będzie nadużywana przez przynajmniej niektóre typy programistów. Tylko przez umiarkowane nadużywanie przez niektórych doświadczonych programistów (nie noobów) reszta doświadczonych programistów poznaje granice właściwego użytkowania. Ekstremalne nadużywanie jest zwykle złe, ale może być dobre, ponieważ takie nadużycia mogą prowadzić do ulepszeń funkcji lub lepszej funkcji zastępującej ją.
Ale gdybym pracował nad kodem z więcej niż kilkoma liniami jak
gdzie typ jest wskazywany zero razy, może chciałbym zmienić te wiersze, aby zawierały typy. Pierwszy przykład jest świetny, ponieważ typ jest podawany jeden raz, i
auto
pozwala nam uniknąć konieczności dwukrotnego pisania niechlujnych typów szablonów. Brawo dla C ++++. Ale wyraźne pokazanie typu zero razy, jeśli nie jest łatwo widoczne w pobliskiej linii, denerwuje mnie, przynajmniej w C ++ i jego bezpośrednich następcach. W przypadku innych języków zaprojektowanych do pracy na wyższym poziomie z większą abstrakcją, polimorfizmem i ogólnością, jest w porządku.źródło
Na C ++ i poza 2012 r. W panelu Ask Us Anything odbyła się fantastyczna wymiana zdań między Andrei Alexandrescu, Scottem Meyerem i Herbem Sutterem na temat tego, kiedy używać, a czego nie
auto
. Przejdź do minuty 25:03, aby rozpocząć 4-minutową dyskusję. Wszystkie trzy głośniki dają doskonałe punkty, o których należy pamiętać, kiedy nie należy ich używaćauto
.Gorąco zachęcam ludzi, aby doszli do własnych wniosków, ale moim zabraniem było używanie
auto
wszędzie, chyba że :Liberalne stosowanie
explicit
pomaga zmniejszyć obawy dotyczące tego drugiego, co pomaga zminimalizować czas, przez który ten drugi stanowi problem.Przypominając, co powiedział Herb, „jeśli nie wykonujesz X, Y i Z, użyj
auto
. Dowiedz się, czym są X, Y i Z, i używajauto
wszędzie indziej”.źródło
Tak, można go nadużywać ze szkodą dla czytelności. Sugeruję używanie go w kontekstach, w których dokładne typy są długie, niewymienne lub nieistotne dla czytelności, a zmienne są krótkotrwałe. Na przykład typ iteratora jest zwykle długi i nie jest ważny, więc
auto
działałoby:auto
tutaj nie szkodzi czytelności.Innym przykładem jest typ reguły parsera, który może być długi i skomplikowany. Porównać:
z
Z drugiej strony, gdy typ jest znany i jest prosty, o wiele lepiej jest, jeśli podano wyraźnie:
zamiast
źródło
begin()
iend()
, lub twój rozmiar kroku jest inny niż jeden, lub gdy modyfikujesz kontener w pętli, instrukcja oparta na zakresie nie pomoże.r_and_t<r_and_t<r_char_t<char>&, r_char_t<char>&>, r_char_t<char>&>
robi?space
jest typ , i poszukać tego. To w każdym razie bardziej użyteczna informacja ... w końcu problemem nie jest „jaki typ jest ta nowa zmienna”, ale „co tospace & space & space
znaczy?” Rzeczywistym rodzajem wyrażenia jest po prostu hałas.auto
może być bardzo niebezpieczne w połączeniu z szablonami wyrażeń, które są często używane przez biblioteki algebry liniowej, takie jak Eigen lub OpenCV.Błędy spowodowane tego typu błędami są dużym problemem podczas debugowania. Jednym z możliwych rozwiązań jest jawne rzutowanie wyniku na oczekiwany typ, jeśli masz ochotę używać auto dla stylu deklaracji od lewej do prawej.
źródło
A*B
wyrażenie jest kopiowane doauto
zmiennej, czy czegoś innego, opisywane zachowanie jest nadal obecne.auto
.diag(A * B)
nie musi marnować cykli obliczania elementów nie przekątnych.Używam
auto
bez ograniczeń i nie napotkałem żadnego problemu. Czasem nawet używam go do takich prostych typów jakint
. To sprawia, że c ++ jest dla mnie językiem wyższego poziomu i pozwala zadeklarować zmienną w c ++ jak w Pythonie. Po napisaniu kodu python nawet czasami piszę npzamiast
Jest to jeden przypadek, w którym powiedziałbym, że jest to nadużycie
auto
słowa kluczowego.Często nie mam nic przeciwko temu, jaki jest dokładnie typ obiektu, bardziej interesuje mnie jego funkcjonalność, a ponieważ nazwy funkcji ogólnie mówią coś o obiektach, które zwracają,
auto
nie boli: na przykładauto s = mycollection.size()
mogę zgadywać, żes
to będzie rodzaj liczby całkowitej, aw rzadkich przypadkach, gdy zależy mi na dokładnym typie, sprawdźmy prototyp funkcji (to znaczy wolę sprawdzać, kiedy potrzebuję informacji, niż a priori, gdy kod jest zapisywany, po prostu na wypadek, gdyby kiedyś był przydatny, jak wint_type s = mycollection.size()
).Odnośnie tego przykładu z zaakceptowanej odpowiedzi:
W moim kodzie nadal używam
auto
w tym przypadku, a jeśli chcęx
być bez znaku, używam funkcji narzędziowej o nazwie saymake_unsigned
, która jasno wyraża moje obawy:zrzeczenie się odpowiedzialności: Po prostu opisuję swoje zastosowanie, nie jestem kompetentny do udzielania porad!
źródło
auto i = MyClass()
.as_unsigned
Jest tam zalecane, a nawetauto w = widget{};
.Jednym z głównych problemów z programem C ++ jest to, że pozwala on na użycie niezainicjowanej zmiennej . To prowadzi nas do nieprzyjemnego, deterministycznego zachowania programu. Należy zauważyć, że nowoczesny kompilator wyświetla teraz odpowiednie komunikaty / komunikaty ostrzegawcze, jeśli program się męczy.
Aby to zilustrować, rozważ poniższy program c ++:
Jeśli skompiluję ten program przy użyciu nowoczesnego kompilatora (GCC), wyświetli ostrzeżenie. Takie ostrzeżenie może nie być bardzo oczywiste, jeśli pracujemy z prawdziwym złożonym kodem produkcyjnym.
================================================== =============================== Teraz, jeśli zmienimy nasz program korzystający z auto , a następnie skompilujemy, otrzymamy:
W przypadku auto nie jest możliwe użycie niezainicjowanej zmiennej. Jest to główna zaleta, którą możemy uzyskać (za darmo), jeśli zaczniemy korzystać z auto .
Ta koncepcja i inne super super nowoczesny C ++ koncepcja wyjaśnia ekspert C ++ Herb migawki w jego CppCon14 Dyskusja:
Powrót do podstaw! Podstawy nowoczesnego stylu C ++
źródło
auto
.auto
- ale nie trzeba go aboid ten problem.Jednym z zagrożeń, które zauważyłem, są odniesienia. na przykład
Problem w tym, że inny_ref nie jest tak naprawdę referencją, w tym przypadku jest to MyBigObject zamiast MyBigObject &. W końcu kopiujesz duży obiekt, nie zdając sobie z tego sprawy.
Jeśli otrzymujesz referencję bezpośrednio z metody, możesz nie myśleć o tym, co to właściwie jest.
potrzebujesz „auto &” lub „const auto &”
źródło
Użyj
auto
tam, gdzie ma to sens, aby wywnioskować typ. Jeśli masz coś, o czym wiesz, że jest liczbą całkowitą lub wiesz, że jest to ciąg znaków, po prostu użyj int / std :: string itp. Nie martwiłbym się o „nadużywanie” funkcji języka, chyba że dojdzie do absurdu, lub zaciemnia kod.W każdym razie taka jest moja opinia.
źródło
auto
Słowo kluczowe może być użyte tylko dla zmiennej lokalnej, a nie do argumentów lub członków klasy / struct. Dzięki temu korzystanie z nich w dowolnym miejscu jest bezpieczne i opłacalne. Często ich używam. Typ jest wywnioskowany w czasie kompilacji, debuger pokazuje typ podczas debugowania,sizeof
raportuje go poprawnie,decltype
daje prawidłowy typ - nie ma szkody. Nigdy nie liczęauto
jako nadużywane, nigdy!źródło
TL; DR: patrz zasada praktyczna na dole.
Odpowiedź Zaakceptowany proponuje następujące równania:
Ale powiedziałbym, że to zbyt restrykcyjne. Czasami nie dbam o typy, ponieważ stwierdzenie to jest wystarczająco pouczające, a ja nie zawracam sobie głowy, aby znaleźć czas na jego opracowanie. Co mam przez to na myśli? Rozważ przykład, który pojawił się w niektórych odpowiedziach:
Co sprawia, że jest to przykład niewłaściwego użycia
auto
? Czy to moja ignorancja co dof()
typu zwrotu? Cóż, może rzeczywiście pomóc, gdybym to wiedział, ale - to nie jest moja główna troska. Problemem jest znacznie więcejx
if()
są one zupełnie bez znaczenia. Gdybyśmy mieli:zamiast tego zwykle nie dbam o to, czy zwracany typ funkcji jest oczywisty, czy nie. Czytając to zdanie, wiem, co robię i wiem wystarczająco dużo o semantyce wartości zwracanej, aby nie czuć, że muszę także znać jej typ.
Więc moja odpowiedź brzmi: używaj,
auto
gdy kompilator na to pozwala, chyba że:I również:
auto
jej konkretnym typem.źródło
Jednym z moich gorzkich doświadczeń
auto
jest używanie go z wyrażeniami lambda :Właściwie tutaj
i
jest rozwiązany wskaźnik funkcjiint(*)()
. Jest to po prostu prostecout
, ale wyobraź sobie, jaki rodzaj złych błędów kompilacji / środowiska wykonawczego może powodować, gdy jest używany ztemplate
.Należy unikać
auto
takich wyrażeń i wstawić odpowiednireturn
typ (lub kontrolowanydecltype()
)Prawidłowe użycie powyższego przykładu to:
źródło
()
zakończyć. Lambdy mają działać jako funkcje i stąd pochodzi konwersja wskaźnika funkcji. Jeśli chcesz to nazwać od razu, po co w ogóle używać lambda?auto i = 0;
działa raczej dobrze.auto x = []() { /* .... whatever goes in here ... */ }()
jest lepszy niżauto x = /* .... whatever goes in here ... */;
, tj. To samo, bez lambda? Uważam to za raczej bezcelowe, z tego samego powoduauto x = 42 + y - 42
jest bezcelowe.