Czytałem, że w C ++ 17 możemy inicjalizować zmienne w if
takich instrukcjach
if (int length = 2; length == 2)
//execute something
Zamiast
int length = 2;
if (length == 2)
//do something
Mimo że jest krótszy, wpływa na czytelność kodu (szczególnie dla osób, które nie znają tej nowej funkcji), co, jak sądzę, jest złą praktyką kodowania w przypadku tworzenia dużego oprogramowania.
Czy korzystanie z tej funkcji ma inne zalety niż skrócenie kodu?
if (int length = 2; length == 2)
może to zaskakujące, widzisz to za pierwszym razem, ale nie jest to nic skomplikowanego, czego nie można by zrozumieć, więc już za drugim razem nie będzie to już duża niespodzianka i deklarowanie rzeczy w zakresie, do którego należy jeden z głównych czynników wpływających na czytelność. IMHO Twój założeniem jest źle;)Odpowiedzi:
Ogranicza zakres
length
doif
samego. Otrzymujesz więc te same korzyści, jakie otrzymaliśmy, kiedy pozwolono nam pisaćfor(int i = 0; i < ... ; ++i) { // ... }
Zamiast przecieku zmiennej
int i; for(i = 0; i < ... ; ++i) { // ... }
Zmienne krótkotrwałe są lepsze z kilku powodów. Ale żeby wymienić kilka:
Im krócej coś żyje, tym mniej rzeczy musisz pamiętać podczas czytania niepowiązanych ze sobą wierszy kodu. Jeśli
i
nie istnieje poza pętlą lubif
instrukcją, nie musimy przejmować się jego wartością poza nimi. Nie musimy też martwić się, że jego wartość będzie oddziaływać z innymi częściami programu, które są poza jego zamierzonym zakresem (co może się zdarzyć, jeślii
powyższe zostanie ponownie użyte w innej pętli). Ułatwia śledzenie kodu i uzasadnienie.Jeśli zmienna przechowuje zasób, to jest on teraz przechowywany przez najkrótszy możliwy okres. I to bez obcych kręconych szelek. Wyjaśniono również, że zasób jest powiązany z
if
samym. Potraktuj to jako motywujący przykładif(std::lock_guard _(mtx); guarded_thing.is_ready()) { }
Jeśli Twoi koledzy nie są świadomi tej funkcji, naucz ich! Uspokajanie programistów, którzy nie chcą się uczyć, to kiepska wymówka, aby unikać funkcji.
źródło
if (auto p = ptr.lock(); p && p->foo()) bar(*p);
{int i = 2; if (i == 2) {...}}
” (zwróć uwagę na dodatkowy zakres).Zmniejszasz zakres zmiennej. Ma to sens i zwiększa czytelność, ponieważ wzmacnia lokalizację identyfikatorów, o których musisz się zastanowić. Zgadzam się, że
if
należy unikać długich instrukcji init w instrukcjach, ale w przypadku krótkich rzeczy jest w porządku.Zauważ, że możesz już wykonać inicjalizację i rozgałęzienie wyniku w wersji przed C ++ 17:
int *get(); // returns nullptr under some condition if (int *ptr = get()) doStuff();
To zależy od osobistej opinii, ale możesz uznać wyraźny warunek za bardziej czytelny:
if (int *ptr = get(); ptr != nullptr) doStuff();
Poza tym argumentowanie przeciwko czytelności funkcji poprzez odwoływanie się do faktu, że ludzie nie są do niej przyzwyczajeni, jest niebezpieczne. W pewnym momencie ludzie nie byli przyzwyczajeni do mądrych wskazówek, ale dzisiaj wszyscy zgadzamy się (chyba), że dobrze, że tam są.
źródło
if (auto p =get ())
ponieważ zdefiniowano operator boolNowa forma instrukcji if ma wiele zastosowań.
Otwórz standardową propozycję instrukcji If z inicjatorem
Podsumowując, ta instrukcja upraszcza typowe wzorce kodu i pomaga użytkownikom zachować ścisłe zakresy.
Mam nadzieję, że to pomoże!
źródło
W celu zminimalizowania zakresu zmiennych istnieje idiom, który definiuje zasób tylko wtedy, gdy jest ważny w momencie tworzenia (na przykład obiekty strumieni plików ):
if(auto file = std::ifstream("filename")) { // use file here } else { // complain about errors here } // The identifier `file` does not pollute the wider scope
Czasami chcesz mieć możliwość odwrócenia logiki tego testu, aby błąd stał się klauzulą podstawową, a prawidłowy zasób
else
klauzulą. Wcześniej nie było to możliwe. Ale teraz możemy zrobić:if(auto file = std::ifstream("filename"); !file) { // complain about errors here } else { // use file here }
Przykładem może być zgłoszenie wyjątku:
if(auto file = std::ifstream(filename); !file) throw std::runtime_error(std::strerror(errno)); else { // use file here }
Niektórzy ludzie lubią kodować tak, aby funkcja przerywała działanie wcześniej w przypadku błędu lub w inny sposób postępuje. Ten idiom fizycznie stawia logikę abortowania ponad logiką kontynuacji, którą niektórzy ludzie mogą uznać za bardziej naturalną.
źródło
Jest to szczególnie przydatne w przypadku zdarzeń logicznych. Rozważmy ten przykład:
char op = '-'; if (op != '-' && op != '+' && op != '*' && op != '/') { std::cerr << "bad stuff\n"; }
Wydaje się trochę szorstkie. Jeśli nie jesteś bardzo zaznajomiony z
OR, AND
negacjami, być może będziesz musiał zatrzymać się i pomyśleć o tej logice - która jest ogólnie kiepskim projektem. Dziękiif-initialization
możesz dodać wyrazistości.char op = '-'; if (bool op_valid = (op == '-') || (op == '+') || (op == '*') || (op == '/'); !op_valid) { std::cerr << "bad stuff\n"; }
nazwana zmienna może być ponownie użyta wewnątrz
if
too. Na przykład:if (double distance = std::sqrt(a * a + b * b); distance < 0.5){ std::cerr << distance << " is too small\n"; }
Jest to świetne, zwłaszcza biorąc pod uwagę, że zmienna ma określony zakres i dlatego nie zanieczyszcza później przestrzeni.
źródło
Jest to rozszerzenie istniejącej funkcji, która zwiększa czytelność w moim doświadczeniu.
if (auto* ptr = get_something()) { }
Tutaj oboje tworzymy zmienną
ptr
i sprawdzamy, czy nie jest zerowa. Zakresptr
jest ograniczony do miejsca, w którym jest ważny. O wiele łatwiej jest przekonać siebie, że każde użycieptr
jest słuszne.Ale co, jeśli mówimy o czymś, co nie przekształca się w
bool
ten sposób?if (auto itr = find(bob)) { }
To nie działa. Ale dzięki tej nowej funkcji możemy:
if (auto itr = find(bob); itr != end()) { }
Dodaj klauzulę mówiącą „kiedy ta inicjalizacja jest prawidłowa”.
W istocie daje nam to zestaw tokenów, które oznaczają „zainicjuj jakieś wyrażenie, a kiedy będzie poprawne, wykonaj jakiś kod. Jeśli nie jest poprawne, odrzuć je”.
Od czasu C ++ 98 było idiomatyczne wykonanie sztuczki testującej wskaźnik. Kiedy już to zaakceptujesz, to rozszerzenie jest naturalne.
źródło