const auto&
wystarczy, jeśli chcę wykonywać operacje tylko do odczytu. Jednak wpadłem na
for (auto&& e : v) // v is non-const
ostatnio kilka razy. To sprawia, że zastanawiam się:
Czy to możliwe, że w niektórych niejasnych przypadkach narożnych korzystanie z odniesień do przekazywania przynosi pewne korzyści w zakresie wydajności w porównaniu z auto&
lub const auto&
?
( shared_ptr
jest podejrzany o niejasne sprawy narożne)
Zaktualizuj Dwa przykłady, które znalazłem w moich ulubionych:
Czy są jakieś wady używania odwołania do const podczas iteracji po typach podstawowych?
Czy mogę łatwo iterować wartości mapy za pomocą pętli for opartej na zakresie?
Skoncentruj się na pytaniu: dlaczego miałbym chcieć używać auto && w oparciu o zakres dla pętli?
auto&&
pętli opartych na zasięgu?Odpowiedzi:
Jedyną zaletą, jaką widzę, jest to, że iterator sekwencji zwraca referencję proxy i musisz operować na tym odwołaniu w sposób inny niż stały. Weźmy na przykład pod uwagę:
To się nie kompiluje, ponieważ rvalue
vector<bool>::reference
zwrócony ziterator
nie będzie wiązał się z odwołaniem do wartości l-wartości innej niż stała. Ale to zadziała:Biorąc to wszystko pod uwagę, nie kodowałbym w ten sposób, gdybyś nie wiedział, że musisz spełnić taki przypadek użycia. Tzn. Nie zrobiłbym tego bezinteresownie, ponieważ powoduje to , że ludzie zastanawiają się, co zamierzasz. A gdybym to zrobił, nie zaszkodziłoby dodać komentarz wyjaśniający, dlaczego:
Edytować
Ten mój ostatni przypadek naprawdę powinien być szablonem, który ma sens. Jeśli wiesz, że pętla zawsze obsługuje odwołanie do serwera proxy,
auto
działałaby równie dobrzeauto&&
. Ale kiedy pętla czasami obsługiwała odwołania niebędące proxy, a czasami odwołania proxy, myślę, żeauto&&
byłoby to preferowane rozwiązanie.źródło
const auto&
gdy chcę, aby kompilator pomógł mi sprawdzić, czy przypadkowo nie modyfikuję elementów w sekwencji.auto&&
w kodzie ogólnym, w którym muszę zmodyfikować elementy sekwencji. Jeśli tego nie zrobię, po prostu będę się tego trzymaćauto const&
.Korzystanie
auto&&
lub odniesienia uniwersalne z zakresu opartefor
-loop ma tę zaletę, że oddaje to, co dostajesz. W przypadku większości typów iteratorów prawdopodobnie otrzymasz aT&
lub aT const&
dla jakiegoś typuT
. Ciekawym przypadkiem jest sytuacja, w której dereferencja iteratora daje tymczasowe: C ++ 2011 ma łagodne wymagania, a iteratory niekoniecznie są wymagane do uzyskania lwartości. Użycie odwołań uniwersalnych odpowiada przekazywaniu argumentów wstd::for_each()
:Przedmiotem funkcji
f
można leczyćT&
,T const&
lubT
w inny sposób. Dlaczegofor
treść pętli opartej na zakresie miałaby być inna? Oczywiście, aby faktycznie skorzystać z wywnioskowania typu przy użyciu uniwersalnych odwołań, musisz je odpowiednio przekazać:Oczywiście użycie
std::forward()
oznacza, że akceptujesz wszystkie zwrócone wartości, z których chcesz przenieść. Czy takie obiekty mają sens w kodzie innym niż szablon, którego nie wiem (jeszcze?). Mogę sobie wyobrazić, że użycie uniwersalnych odwołań może dostarczyć kompilatorowi więcej informacji, aby wykonać właściwą rzecz. W kodzie opartym na szablonach nie podejmuje żadnych decyzji dotyczących tego, co powinno się stać z obiektami.źródło
Praktycznie zawsze używam
auto&&
. Po co dać się ugryźć przez skrajny przypadek, kiedy nie musisz? Jest też krótszy do pisania i po prostu uważam, że jest bardziej ... przejrzysty. Kiedy używaszauto&& x
, wiesz, żex
tak jest za*it
każdym razem.źródło
const
poddajesz się,auto&&
jeśliconst auto&
wystarczy. Pytanie dotyczy narożnych przypadków, w których mogę zostać ugryziony. Jakie są przypadki narożne, o których jeszcze nie wspomniał Dietmar ani Howard?auto&&
. Jeśli typ, który przechwytujesz, powinien zostać przeniesiony w treści pętli (na przykład) i zostanie zmieniony na późniejszy, tak aby przekształcił się wconst&
typ, twój kod będzie po cichu nadal działać, ale twoje ruchy będą kopiami. Ten kod będzie bardzo zwodniczy. Jeśli jednak wyraźnie określisz typ jako odniesienie do wartości r, ktokolwiek zmieni typ kontenera, otrzyma błąd kompilacji, ponieważ naprawdę chciałeś, aby te obiekty zostały przeniesione, a nie skopiowane ...for (std::decay_t<decltype(*v.begin())>&& e: v)
? Myślę, że jest lepszy sposób ...auto&&
da "uniwersalne odniesienie", więc cokolwiek innego niż to da ci bardziej szczegółowy typ. Jeśliv
przyjmuje się, że jest avector
, możesz to zrobićdecltype(v)::value_type&&
, co, jak zakładam, chciałeś, biorąc wynik zoperator*
typu iteratora. Możesz równieżdecltype(begin(v))::value_type&&
sprawdzić typy iteratora zamiast kontenera. Jeśli jednak mamy tak mało wglądu w typ, możemy uznać, że trochę jaśniej byłoby po prostu pójść zaauto&&
...