Это очевидная ошибка, вне всякого сомнения.
Цель предупреждения НЕ состоит в том, чтобы предупредить обо всех разделах программы. Это было бы слишком шумно в любой разумной программе. Вместо этого цель состоит в том, чтобы предупредить вас, когда вам нужно проверить аргумент. В этом случае вы проверили аргумент. Следовательно, компилятор должен был отметить это и заткнуться.
Техническая реализация такой функции осуществляется путем пометки переменных в ветвях кода определенными атрибутами. Один из наиболее распространенных атрибутов - это три состояния «Нулевое значение». Перед ветвью arg
является внешней переменной, а arg [[Isnull]]
неизвестен. Но после проверки на arg
есть две ветки. В первой ветке arg [[Isnull]]
истинно. Во второй ветке arg [[Isnull]]
ложно.
Теперь, когда дело доходит до генерации предупреждений о делении на ноль и нулевом указателе, следует проверить атрибут [[IsNull]
. Если это правда, у вас серьезное предупреждение / ошибка. Если неизвестно, вы должны сгенерировать показанное выше предупреждение - потенциальная проблема, превышающая то, что может доказать компилятор. Но в этом случае атрибут [[isNull]]
имеет значение False. Компилятор, руководствуясь той же формальной логикой, что и люди, знает, что риска нет.
Но как мы узнаем, что компилятор использует такой атрибут [[Isnull]]
внутри? Вспомните первый абзац: без него пришлось бы либо предупреждать всегда, либо никогда. Мы знаем, что иногда он предупреждает, поэтому должен быть атрибут [[IsNull]]
.
[[isNull]]
имеет значение False. Компилятор, руководствуясь той же формальной логикой, что и люди, знает, что риска нет.
Но как мы узнаем, что компилятор использует такой атрибут [[Isnull]]
внутри? Вспомните первый абзац: без него пришлось бы либо предупреждать всегда, либо никогда. Мы знаем, что иногда он предупреждает, поэтому должен быть атрибут [[IsNull]]
.
[[isNull]]
имеет значение False. Компилятор, руководствуясь той же формальной логикой, что и люди, знает, что риска нет.
Но как мы узнаем, что компилятор использует такой атрибут [[Isnull]]
внутри? Вспомните первый абзац: без него пришлось бы либо предупреждать всегда, либо никогда. Мы знаем, что иногда он предупреждает, поэтому должен быть атрибут [[IsNull]]
.
Условный оператор не должен оценивать все аргументы. Но я считаю, что вы можете взять arg
почти равным 0, поэтому arg == 0.0
будет false
, но 1./arg
даст результат "деление на ноль". Так что я думаю, что это предупреждение здесь полезно.
Кстати, Visual C ++ 2008 не выдает такого предупреждения.
operator == для чисел с плавающей запятой небезопасен (т. Е. Ему нельзя доверять из-за проблем с округлением). В данном конкретном случае это действительно безопасно, поэтому вы можете проигнорировать предупреждение, но компилятор не будет проводить такой анализ на основе оператора, результаты которого в общем случае несколько непредсказуемы.
Компилятор не может статически анализировать все пути кода и постоянно учитывать все возможности. Теоретически полный анализ поведения программы, просто заглянув в ее исходный код, может предоставить решение проблемы остановки, которая неразрешима. Компиляторы имеют ограниченный набор правил статического анализа для обнаружения правил. Стандарт C ++ не требует, чтобы компилятор выдавал подобные предупреждения, поэтому нет. Это не ошибка. Это больше похоже на несуществующую функцию.
В дополнение к другим комментариям: предупреждение генерируется компилятором, мертвая ветвь удаляется оптимизатором, который запускается позже - возможно, даже на этапе связывания.
Так что нет, это не ошибка. Предупреждение - это дополнительная услуга, предоставляемая компилятором, не предусмотренная стандартом. Это неприятный побочный эффект архитектуры компилятора / компоновщика.
будет сгенерирован код подразделения, отсюда и предупреждение. но ветвление никогда не будет выполнено, если arg
равно 0, так что это безопасно.
Вы можете избежать появления предупреждения, используя специфичное для Microsoft ключевое слово __ accept
. Я не уверен, можно ли связать это с условным оператором. В противном случае стоит попробовать что-нибудь вроде
if (arg == 0.0){
return 0.0;
}
else {
__assume(arg != 0.0);
return 1./arg;
}
. Или, конечно, просто отключите предупреждение во время этой функции с помощью соответствующей #pragma
.
Нет, условный оператор не оценивает оба аргумента. Однако обычно сообщается о потенциальном делении на ноль, если компилятор может обнаружить такую вещь. Не зря стандарт занимает ~ 2 страницы для описания поведения этого оператора.
Из N-4411:
5.16 Условный оператор
1 Группа условных выражений справа налево. Первое выражение контекстно преобразуется в логическое значение (пункт 4). Он оценивается, и если это правда, результат условного выражение - это значение второго выражение, иначе выражение третье выражение. Только один из второе и третье выражения оценен. Расчет каждого значения и побочный эффект, связанный с первым выражение упорядочивается перед каждым вычисление значения и побочный эффект связанный со вторым или третьим выражение.
Также обратите внимание:
3 В противном случае, если второй и третий операнды бывают разных типов, и либо имеет (возможно, квалифицированное резюме) тип класса, делается попытка преобразовать каждый из этих операндов в тип другого.
В приведенном вами примере один и тот же тип для второго и третьего выражений - будьте уверены, будет вычислено только первое.