Czytając niektóre przykłady pętli opartych na zakresie, sugerują dwa główne sposoby 1 , 2 , 3 , 4
std::vector<MyClass> vec;
for (auto &x : vec)
{
// x is a reference to an item of vec
// We can change vec's items by changing x
}
lub
for (auto x : vec)
{
// Value of x is copied from an item of vec
// We can not change vec's items by changing x
}
Dobrze.
Kiedy nie potrzebujemy zmieniać vec
elementów, IMO, Przykłady sugerują użycie drugiej wersji (według wartości). Dlaczego nie sugerują czegoś, do czego się const
odwołują (Przynajmniej nie znalazłem żadnej bezpośredniej sugestii):
for (auto const &x : vec) // <-- see const keyword
{
// x is a reference to an const item of vec
// We can not change vec's items by changing x
}
Czy to nie jest lepsze? Czy nie unika się zbędnej kopii w każdej iteracji, gdy jest to const
?
const auto &x
jest to odpowiednik twojego trzeciego wyboru.auto&&
gdy nie chcesz tworzyć niepotrzebnej kopii i nie przejmuj się, czy ją zmodyfikujesz, czy nie, a chcesz po prostu pracować.const
z pewnością skorzystam. Jednak czy będzieauto const &
, czyauto const
ma niewielką różnicę. Wolałbymauto const &
być bardziej konsekwentny.Jeśli masz
std::vector<int>
lubstd::vector<double>
, możesz użyćauto
(z kopiowaniem wartości) zamiastconst auto&
, ponieważ kopiowanieint
lubdouble
jest tanie:Ale jeśli masz
std::vector<MyClass>
, gdzieMyClass
jest trochę nietrywialna semantyka kopiowania (np.std::string
Niektóre złożone klasy niestandardowe itp.), To sugeruję użycie wconst auto&
celu uniknięcia głębokich kopii :źródło
Następnie podają niewłaściwą sugestię.
Ponieważ podają niewłaściwą sugestię :-) To, o czym wspominasz, jest poprawne. Jeśli chcesz tylko obserwować obiekt, nie ma potrzeby tworzenia kopii i nie ma potrzeby
const
odwoływania się do niego.EDYTOWAĆ:
Widzę, że wszystkie odnośniki zawierają przykłady iteracji w zakresie
int
wartości lub innego podstawowego typu danych. W takim przypadku, ponieważ kopiowanieint
nie jest drogie, tworzenie kopii jest zasadniczo równoważne (jeśli nie bardziej wydajne niż) obserwowaniuconst &
.Nie dotyczy to jednak ogólnie typów zdefiniowanych przez użytkownika. Kopiowanie UDT może być kosztowne, a jeśli nie masz powodu do tworzenia kopii (np. Modyfikowania odzyskanego obiektu bez zmiany oryginalnego), najlepiej jest użyć
const &
.źródło
Będę tu przeciwny i powiem, że nie ma potrzeby
auto const &
w zakresie opartym na pętli. Powiedz mi, jeśli uważasz, że poniższa funkcja jest głupia (nie w swoim celu, ale w sposobie, w jaki jest napisana):Tutaj autor stworzył stałe odwołanie do
v
użycia dla wszystkich operacji, które nie modyfikują v. To jest, moim zdaniem, głupie, a ten sam argument można zastosowaćauto const &
jako zmienną w zakresie opartym na pętli zamiast po prostuauto &
.źródło
const_iterator
w pętli for? W jaki sposób upewniasz się, że nie zmieniasz oryginalnych przedmiotów z pojemnika podczas iteracji?const_iterator
? Niech zgadnę, pojemnik, nad którym iterujesz, jestconst
. Ale od czego toconst
się zaczyna? Gdzieś używasz,const
aby się upewnić?const
są zalety używaniaprivate
/protected
w klasach. Pozwala to uniknąć dalszych błędów.v
, wdrożenie będzie w porządku IMO. A jeśli pętla nigdy nie modyfikuje obiektów, przez które się iteruje, wydaje mi się słuszne, aby mieć referencjęconst
. Rozumiem jednak twój punkt widzenia. Mój polega na tym, że pętla reprezentuje jednostkę kodu, podobnie jak funkcja, i wewnątrz tej jednostki nie ma instrukcji, która musiałaby modyfikować wartość. Dlatego można „oznaczyć” całą jednostkę jakoconst
, tak jak w przypadkuconst
funkcji członka.const &
oparte na zakresie jest głupie, ponieważ napisałeś nieistotny wyimaginowany przykład wyimaginowanego programisty, który zrobił coś głupiego z kwalifikacją cv ? ... OK więc