На даний момент я налагоджую деякий код і натрапив на цей рядок:
for (std::size_t j = M; j <= M; --j)
(Написав мій начальник, який у відпустці.)
Мені це здається по-справжньому дивним.
Що це робить? Для мене це схоже на нескінченну петлю.
На даний момент я налагоджую деякий код і натрапив на цей рядок:
for (std::size_t j = M; j <= M; --j)
(Написав мій начальник, який у відпустці.)
Мені це здається по-справжньому дивним.
Що це робить? Для мене це схоже на нескінченну петлю.
Mце максимальне значення для size_t? Ти все ще вважаєш, що це розумно?
#define TRUE FALSEі поїхати у відпустку.
Відповіді:
std::size_tгарантується стандартом C ++ як unsignedтип. І якщо ви зменшуєте unsignedтип від 0, стандарт гарантує, що результат цього є найбільшим значенням для цього типу.
Це обернене значення завжди більше або дорівнює M1, тому цикл завершується.
Отже, j <= Mколи застосовується до unsignedтипу, це зручний спосіб сказати "запустіть цикл до нуля, а потім зупиніть".
Існують такі варіанти, як запуск jбільшого, ніж ви хочете, і навіть використання оператора слайдів for (std::size_t j = M + 1; j --> 0; ){ , які, безперечно, зрозуміліші, хоча вимагають більше введення тексту. Я думаю, що одним недоліком (крім здивовального ефекту, який він виробляє під час першої перевірки) є те, що він погано портує на мови без непідписаних типів, таких як Java.
Також зауважте, що схема, яку вибрав ваш начальник, "запозичує" можливе значення з unsignedнабору: у цьому випадку трапляється, що Mнабір std::numeric_limits<std::size_t>::max()не матиме правильної поведінки. Насправді в цьому випадку цикл нескінченний . (Це те, що ви спостерігаєте?) Вам слід вставити коментар з цього приводу в код і, можливо, навіть заявити про цю конкретну умову.
Mвідсутності std::numeric_limits<std::size_t>::max().
std::numeric_limits<std::size_t>::max()тоді M + 1буде нулем, а for (std::size_t j = M + 1; j --> 0; )цикл взагалі не буде циклічним.
size_tце 64 біти, знадобиться кілька сотень років, щоб спостерігати некоректну поведінку в крайньому випадку. (За винятком випадків, коли оптимізатор може позбутися циклу.)
Те, що, напевно, намагався зробити ваш начальник, це зворотний відлік Mдо нуля включно, виконуючи певні дії з кожним номером.
На жаль, існує такий крайній випадок, коли це справді дасть вам нескінченний цикл, де Mє максимальне size_tзначення, яке ви можете мати. І, хоча добре визначено, що значення без підпису буде робити, коли ви зменшуєте його з нуля, я стверджую, що сам код є прикладом недбалого мислення, тим більше, що існує цілком життєздатне рішення без недоліків спроб ваших босів.
Цей безпечніший варіант (і більш читабельний, на мій погляд, при збереженні жорсткого обмеження обсягу), буде:
{
std::size_t j = M;
do {
doSomethingWith(j);
} while (j-- != 0);
}
Для прикладу див. Наступний код:
#include <iostream>
#include <cstdint>
#include <climits>
int main (void) {
uint32_t quant = 0;
unsigned short us = USHRT_MAX;
std::cout << "Starting at " << us;
do {
quant++;
} while (us-- != 0);
std::cout << ", we would loop " << quant << " times.\n";
return 0;
}
Це робить в основному те саме, що і, unsigned shortі ви можете бачити, що він обробляє кожне окреме значення:
Starting at 65535, we would loop 65536 times.
Заміна do..whileциклу у наведеному вище коді тим, що в основному робив ваш бос, призведе до нескінченного циклу. Спробуйте і подивіться:
for (unsigned int us2 = us; us2 <= us; --us2) {
quant++;
}
0. Чому ні for(size_t j = M; j-- != 0; )?
numeric_limits<size_t>::max().
M == 0призведе до елементу-не обробляються, тому він робить є крайній випадок. Використання мого do..whileметоду пост-перевірки взагалі виключає крайовий регістр. Якщо спробувати M == 1, ви побачите, що він робить і 1, і 0. Аналогічно, почніть з max_size_t(що б там не було), і він успішно почнеться в той момент, а потім зменшиться до нуля включно.
exitif”, а саме { j =M; for(;;){ f(j); if( j == 0 )break; j -= 1; } }. Один не може навіть потрібно замінити breakз , gotoякщо речами отримати вкладені, так як C має не названі петлі. Якщо "структурований" означає "сприйнятливий до міркувань про шматки", він структурований (макет допомагає!), А також якщо означає "сприйнятливий до формальної перевірки шляхом міркувань щодо попередніх та післяумов". Хоча в цьому випадку це j--працює, стиль існування може бути виправданим, коли потрібен більш складний перехід.
size_tне підписаний, тому гарантовано обернеться до максимального значення при спробі припинити нуль, закінчуючи цикл. Все ще жахливий код.