2017-02-09 28 views
0

Я пытаюсь решить, следует ли использовать исключения, утверждения или пограничные проверки в некоторых моих кодах.Проверка входных параметров

Программа содержит множество вычислений, которые зависят от пользовательского ввода. Программа работает во встроенной системе.

Приведенный ниже код является типичным примером. 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% и оставить код как есть, но другие функции напрямую не зависят от пользовательского ввода, а являются результатом других вычислений.

Каков наилучший способ обработки плохих входных параметров в этих типах функций?

ответ

0

ли не усилия исключения на пользователей вашего класса, а позволяют им сделать это, если они хотят.

  • Обеспечить validWeightValue(x) функцию, которая возвращает true если x является допустимым значением для weight_percent_salt.

  • Сообщите, что 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кодов возврата, если у вас нет дополнительного состояния, связанного с условием ошибки.

+0

Это выглядит как хороший способ сделать это. В моем случае пользовательский ввод будет проходить через последовательный порт с использованием Modbus RTU, поэтому я бы просто вернул код ошибки вместо того, чтобы бросать исключение, если входные данные находятся за пределами указанных значений. Спасибо за ответ! –

+0

@ Q-bertsuit: да, конечно, избегайте исключений, если вам это удастся. 'std :: optional', коды ошибок и аналогичные решения, на мой взгляд, более надежны, поскольку они используют систему типов и вынуждают пользователя справляться с ними. –

+0

Приятно, я посмотрю std :: optional, хотя компилятор для этого конкретного проекта даже не поддерживает C++ 11. –

0

Утверждения: Обычно они включаются только для отладочных сборников и приводят к сбою. Так как они обычно отключены для релизов, вы можете захотеть следить за другим механизмом повышения ошибки; поскольку их основная задача - объявить разработчику, что состояние программы является тем, которое, по мнению разработчика, невозможно. Очевидно, что для пользовательского ввода все возможно, и это не подходит.

(почти) Все остальное: Выполняется как для сборки отладки, так и для выпуска; поэтому для того, где пользователь вводит информацию, гораздо предпочтительнее. Exaclty, что «что-то еще», зависит от того, как вы планируете иметь дело с провалом, что в значительной степени является вопросом мнения.

Сказанное: Исключения должны быть «исключительными» в том, что они не только часто случаются; который, вероятно, неприменим для синтаксического анализа пользовательского ввода.

+0

Проблема в том, что невозможно предсказать каждую комбинацию плохих пользовательских входных данных, и я должен иметь некоторый способ сообщить, что пошло не так. Если я не могу использовать исключения (которые, я согласен, должен быть зарезервирован для таких вещей, как нехватка памяти и т. Д.), У меня остались коды возврата, и они имеют тенденцию загромождать мой код. –

+0

Учитывая, что Витторио подчеркнул об исключениях - я просто хотел осветить утверждения; поскольку они совершенно не подходят для изучения ввода пользователя. Что касается бросков, никто не сказал «не использовать», но «не заставляйте» - то есть вы можете сделать версию класса с кодами возврата, а затем класс-оболочку, который проверяет коды возврата и бросает. (или даже просто поставить флаг в классе и бросить в зависимости от этого) – UKMonkey