2009-06-18 3 views
6

Последний вопрос на сегодня все ... Я вернусь с tomorrow..I есть много, чтобы следить за ...Используя! = Со счетчиком контролируемых шлейфов

Я ищу в Рейли Java Шрифтом- говорить (не имеет значения, на каком языке ..)

Автор для контрконтрольных циклов (для, в то время как и т. д.) и с петлями вложенности ... использует! = для теста ... Теперь Я понимаю! = Используется для определенных ситуаций с управляемыми событиями петлями-подобными дозорными или EOF-типами циклов, но для меня - использование его с контррегулируемым контуром - плохая идея ... очень склонна к ошибкам.

Примеры:

x = 0; 
while (x != 100) { 
    y = 0; 
    while (y != 100) { 

    ... 
    y++; 
} 
    x++; 
} 

было бы лучше просто say..using другие реляционные операторы ...

x = 0; 
while (x < 100) { //or even better some defined constant... 
    y = 0; 
    while (y < 100) { 

    ... 
    y++; 
} 
    x++; 
} 

Что из того, что я видел, как правило, способ представлен в texts..classes Т.д. ..

После снова- бы все, что вы считали это bad- или просто другой способ сделать это ... Спасибо ...

+1

Предполагая, что 'x' и' y' являются целыми типами, что сделало бы версию '! =' Более подверженной ошибкам? –

+4

Если кто-то ошибочно устанавливает x в 101 внутри цикла, цикл будет продолжать работать. –

+0

Понял, что это одно и то же ... – iwanttoprogram

ответ

5

другие ответы показали,
while(i < 100) безопасен *,
while(i != 100) точен **.

В качестве альтернативы, вы можете попробовать while(i++ < 100) или for(i = 0; i < 100; ++i) вместо более простого цикла, который вы показали - забывая увеличивать счетчик в конце цикла, это настоящая боль.Обратите внимание, что если i=0, i++ будет равно 0, а затем увеличит i в следующий раз, а ++i будет увеличивать i и затем равен 1, поэтому для while(i++ < 100) необходим оператор postfix ++.

Также обратите внимание, что если i было 0, когда оно было проверено в условии, то оно будет 1 в теле цикла (для примера while), поэтому, если i является индексом для массива или что-то еще, а не просто отслеживая циклические итерации, вам лучше придерживаться только цикла for (который увеличивает i после каждой итерации).


*: сейф здесь означает меньше шансов войти в бесконечный цикл. Это также небезопасно в том смысле, что он может скрыть потенциальные ошибки, если цикл не является тривиальным.

**: точный, если он не делает то, что вы ожидаете от него, это не удастся, и вы заметите. Некоторые другие ответы также описали, как еще больше защитить вас от ошибок в этом типе цикла.

+0

- Пойду с этим ответом ... – iwanttoprogram

1

Я считаю, что они семантический одинаково, единственное различие, заключающееся в том, что: = числа выше 100, очевидно, также будет соответствовать условию, когда < предотвратит прохождение любого числа, превышающего 100.

Однако в данном случае оба оператора приведут к тому же выводу. Теперь, если каким-то образом переменные x и y будут действовать вне этого кода, «<» будет лучшим способом убедиться, что было обрезание на 100, даже если они вступили со значением 90 и не смогли продолжайте вообще, если они вступят со значением 4000. Очевидно, что намерение того, что вы делаете в то время, будет определять, какой оператор вы выбрали, обычно существует несколько методов для достижения одного и того же результата, а не всегда один «правильный» способ.

+0

Это не показано в примере OPs, но это хорошая точка. При тестировании на x! = 100, что происходит, когда ваш код перескакивает x от 99 до 101? – AllenG

6

Я хотел бы использовать только

while (x != 100) 

, если я хотел петлю прекратить, когда х был точно 100. Таким образом, в подавляющем большинстве случаев я использовал бы

while (x < 100) 

который является более распространены для контуров, управляемых контурами.

EDIT: На второй мысли, я всегда использую для-синтаксиса в противотоке управлением петли, так что пример должен быть

for(int i=0; i < 100; ++i) 
+3

+1 Это идиоматично на Java; не возитесь с тем, что не сломалось. –

+0

По-видимому, автор любит использовать циклы с циферблатами – iwanttoprogram

-1

Это лучше использовать менее < в петле. Существует вероятность того, что ошибка в коде заставит счетчик увеличиваться дважды. Это означает, что цикл внезапно станет бесконечным циклом (или пока вы не нажмете MAXINT).

+0

Лучше, потому что он маскирует ошибки? – Tom

+0

HAHAHAHAHA! Ну, когда вы так выразились ... Это стало принято, потому что вы предполагаете, что в какой-то момент могут быть добавлены ошибки, а цикл, не выполняющий его задачу, предпочтительнее бесконечного цикла. – Kieveli

0

Да. Они семантически одинаковы.

Второй синтаксис с использованием оператора «<» - это один человек в общем случае в этом случае и кажется более интуитивным (поскольку значение переменной увеличивается в цикле).

6

Вы хотите, чтобы ваше условие цикла являлось точным обратным желаемому постусловию.

i= 0; 
while(i != 100) { 
    i += 1; 
} 
assert i == 100; 

Вы можете тривиально видеть, что пост-условие цикла точно соответствует условию завершения цикла. Никаких тайн.

Кроме того, вы можете доказать, что из начального состояния и тела он достигнет 100 без «каким-то образом», магически пропускающего значение.

В случае, когда у вас действительно сложный корпус цикла, эта простая параллельная структура необходима.

Если вы используете Weakest Precondition techniques для получения цикла из пост-состояния, условие цикла будет простым условием согласования, как показано выше.

i < 100 - плохая идея, потому что ваша петля может иметь неправильное тело, которое сильно увеличивало переменную и все еще «появлялось» для работы.

+0

В этом примере нет магии, но может быть, если начальное условие или значение приращения неизвестны до времени выполнения. –

+0

Даже если вещи не известны до времени выполнения, метод WP даст правильный цикл - который завершается - и он всегда будет иметь самое слабое возможное условие завершения в цикле. Он также может давать защиту (if-statement) как предварительное условие, чтобы предотвратить выполнение цикла вообще, если границы приведут к циклу без конца. –

+0

Почему бы не использовать i <100 * AND * assert i == 100? С тем, как вы его представили, если 100 будет пропущено, цикл никогда не завершится, и вы никогда не получите возможность утверждать, правильно ли оно или нет. С помощью моего метода вы получаете гарантию, что она равна 100, без застревания в бесконечном цикле. Лучшее из обоих миров, нет? – mpen

6

Использование < более распространено в Java. Современный C++ использует !=.

!= с большей вероятностью поймает ошибки в вашем коде. В большинстве случаев это хорошо. Если по какой-то причине счетчик не только достиг, но прошел мимо границы (обычно на первой итерации), то тело будет выполняться с незаконным значением. Пока тело цикла не скрывает ошибок, вы получите исключение. Если тело скрывает ошибки, цикл будет выполняться миллиарды раз, и должно быть очевидно, что есть ошибка.

В качестве примера, интересная уязвимость была обнаружена при реализации Adobe Flash в прошлом году. Указатель, используемый как массив, может быть инициализирован как null. Обычно это не проблема - процесс безопасно вылетает всякий раз, когда он сначала разыменовывается. Однако был использован цикл с <, позволяющий телу никогда не выполняться, что затем позволяет продолжить выполнение. После этого память может быть записана в указанном местоположении злоумышленника. Поскольку значение null всегда равно 0, злоумышленник точно знает, к каким ячейкам памяти записывается. Этого не произошло бы, если бы цикл использовал !=.

+0

Да, но цикл, выполняемый миллиардами раз, не является лучшим методом обнаружения ошибок. – cdmckay

+0

@cdmckay: Почему бы и нет? Трудно пропустить. –

+0

@James Curran: Очень правдоподобно, что большая ошибка (так же большая, как счетчик не работает должным образом) никогда не должна проходить мимо первого обзора кода, поэтому вы должны сделать все, что в ваших силах, чтобы убедиться, что вы найдете его как можно скорее. Мне нравится бросать идею исключения, о которой упоминал cdmckay, должен признать, что я никогда не думал об этом сам. –

3

Я не думаю, что < обязательно предлагает вам больше защиты, чем! =. Если у вас есть случай, когда i увеличивается по мере того, как вы не участвуете в этом, вы должны бросать исключение, а не подметать его под ковер с помощью <.

Например, если вы действительно беспокоитесь о своем, а петли Мессинг, вы могли бы сделать что-то вроде этого:

x = 0; 
while (x != 100) 
{ 
    assert x >= 0; 
    assert x < 100; 

    y = 0; 
    while (y != 100) 
    {  
    assert y >= 0; 
    assert y < 100; 

    ... 
    y++; 
    } 
    x++; 
} 

Таким образом, в тот момент, ваш цикл выходит за пределы, ваша программа умирает сразу (крах рано, авария часто), и вы знаете, что ваш код испорчен.

+0

Мое единственное предложение может состоять в том, чтобы сделать это утверждением, чтобы его можно было отключить, когда вы освобождаете его по соображениям производительности (или оставляете его все время, если это то, что вы хотите!) –

+0

Хорошая точка ... также может быть полезно утверждают также нижнюю границу, если вы испортите в другом направлении. – cdmckay

4

Главное преимущество использования «! =» Над «<» - это то, что будет терпеть неудачу, он должен потерпеть неудачу большой.

Например, если ошибка где-то заставляла x вводить цикл, установленный в 110, тогда x < 100 никогда не войдет в цикл - факт, который вы могли бы пропустить при отладке. OTOH, если вы используете x!=100, он никогда не выйдет из цикла - что-то, что не может отсутствовать при отладке.

+0

+1: Хорошее резюме. Вы хотите, чтобы все режимы отказа были обнаружены. –

2

Я подозреваю, что это может иметь какое-то отношение к итераторам на C++.

Если вы используете целые числа или указатели, то < имеет четко определенное значение. Если вы используете итераторы C++ в цикле, < не может быть определен или может быть сложно рассчитать.

Например, в управлении по списку, то, как C++ будет:

for(std::list<foo>::const_iterator i = bar.begin(); i != bar.end(); ++i) 

и действительно единственный способ, чтобы увидеть, если я есть до bar.end() является приращение I на неопределенное время и посмотреть, если он всегда равен bar.end().

Существует значительная ценность при выполнении незначительных вещей одинаково все время.

+0

+1 Я начинал отчаиваться, я не мог поверить, что никто не указал на это! –

Смежные вопросы