Я пытаюсь решить, следует ли мне использовать исключения, утверждения или проверки границ в некоторых моих кодах.
Программа содержит много расчетов, которые зависят от ввода пользователя. Программа работает на встроенной системе.
Код ниже является типичным примером. Параметр weight_percent_salt, очевидно, не должен быть отрицательным и не должен превышать 100.
float Conductivity(const float weight_percent_salt)
{
float sigma_20C = 0.0;
if(weight_percent_salt > 16.2)
{
sigma_20C = 19.4;
}
else
{
sigma_20C = 2.0487 * weight_percent_salt - 0.2352 * pow(weight_percent_salt,2) + 0.0187 * pow(weight_percent_salt,3);
}
return sigma_20C;
}
В этом конкретном случае я могу ограничить ввод данных пользователем от 0 до 100% и оставить код как есть, но другие функции напрямую не зависят от ввода пользователя, а скорее являются результатом других вычислений.
Каков наилучший способ обработки неверных входных параметров в этих типах функций?
Утверждает:
Обычно они включены только для отладочных сборок и приводят к сбою. Поскольку они обычно отключены для сборок релиза, вы можете использовать другой механизм выдачи ошибки; поскольку их основная задача — указать разработчику, что состояние программы такое, что, по мнению разработчика, невозможно.
Очевидно, что для пользовательского ввода все возможно, и это не подходящий выбор.
(Почти) Что-нибудь еще:
Выполняется как для отладочной, так и для релизной сборки; поэтому, когда речь идет о пользовательском вводе, это гораздо предпочтительнее. То, что является «чем-то еще», зависит от того, как именно вы планируете справиться с неудачей, что во многом зависит от мнения.
При этом исключения должны быть «исключительными», поскольку они не только не случаются часто; что, вероятно, не применимо для анализа пользовательского ввода.
Не делайте сила исключения для пользователей вашего класса, вместо разрешать им делать это, если они хотят.
Обеспечить validWeightValue(x)
функция, которая возвращает true
если x
является допустимым значением для weight_percent_salt
,
Делать Conductivity
Предположим, что weight_percent_salt
действует в рамках своего договора.
bool isValidWeightPercentSalt(const float x) noexcept
{
return x >= 0.f && x <= 100.f;
}
float Conductivity(const float weight_percent_salt)
{
assert(isValidWeightPercentSalt(weight_percent_salt));
// ...
}
Теперь пользователь может использовать isValidWeightPercentSalt
на его стороне, чтобы проверить ввод и выдать исключение. Пользователь знает, что Conductivity
предполагает свой аргумент, чтобы удовлетворить isValidWeightPercentSalt
сказуемое.
float calculateConductivityViaUserInput()
{
float percent;
std::cin >> percent;
if(!isValidWeightPercentSalt(percent))
{
throw InvalidPercentUserInput{percent};
}
return Conductivity(percent);
}
Обратите внимание, что я не фанат исключений — если ваш дизайн это позволяет, вернуть обработка монадических ошибок класс как std::optional
, std::variant
или же boost::expected
вместо того, чтобы бросить исключение. В качестве альтернативы рассмотрите возможность использования enum class
из коды возврата если у вас нет дополнительного состояния, связанного с ошибкой.