Я усвідомлюю, що, хоча питання не має мовної позначки, воно, мабуть, неявно говорить про "мови кави". Але просто задля повноти я хотів би зазначити дещо розбіжний очевидний консенсус у світі C ++.
Існує три речі, які зазвичай цікавлять програмістів на C ++:
- Чи буде вона мати нульові накладні витрати в оптимізованих складах? (Тобто чи можна його "скласти"?)
- Чи можу я скористатися нею, щоб потрапити у відладчик прямо в точці, де виявлена помилка?
- Чи можу я використовувати його для повідомлення про проблеми із оголошених функцій
noexcept?
Раніше я підходив до першої проблеми, написавши подібний код
int
factorial(const int n)
{
if (CHECK_ARGS)
{
if (n < 0)
throw std::invalid_argument {"n < 0"};
}
int fac = 1;
for (int i = 2; i <= n; ++i)
fac *= i;
return fac;
}
де CHECK_ARGSзнаходиться #defined до постійна часу компіляції тому компілятор може повністю усунути всі аргумент коди перевірки в оптимізованої збірці. (Я не кажу, що компіляція виписок - це взагалі гарна річ, але я вважаю, що користувач повинен мати можливість їх складати.)
Мені все одно подобається у цьому рішенні, що код перевірки аргументів добре видно, згрупований у if. Однак друге і третє питання цим не вирішуються. Тому я знову більше схиляюся до використання assertмакросу для перевірки аргументів.
Стандарти кодування Boost погоджуються з цим:
Що з помилками програміста?
Як розробник, якщо я порушив попередню умову бібліотеки, яку я використовую, я не хочу відмовляти стек. Що я хочу, це основний дамп або його еквівалент - спосіб перевірити стан програми в точній точці, де була виявлена проблема. Це зазвичай означає assert()або щось подібне.
На CppCon'14 під назвою Оборонне програмування зроблено право ( частина 1 , частина 2 ) була дуже цікава розмова Джона Лакоса . У першій частині своєї бесіди він обговорює теорію договорів та невизначену поведінку. У другій частині він подає те, що вважаю дуже хорошою пропозицією щодо систематичної перевірки аргументів. По суті, він пропонує макроствердження, які дозволяють користувачеві вибирати, яку частину бюджету (з точки зору використання процесора) вона готова пожертвувати бібліотеці для перевірки аргументів і змушує бібліотеку розумно використовувати цей бюджет. Крім того, користувач також може встановити глобальну функцію обробки помилок, яка буде викликана у випадку виявлення порушеного договору.
Щодо аспекту, що функція приватна, я не думаю, що це означає, що ми ніколи не повинні її перевіряти її аргументи. Ми можемо більше довіряти власному коду, щоб не порушувати договір внутрішньої функції, але також знаємо, що і ми не є ідеальними. Перевірка аргументів у внутрішніх функціях так само корисна при виявленні наших власних помилок, як і в загальнодоступних функціях виявлення помилок у коді клієнта.