Коротка відповідь: читання Розумною Обробка помилок 1 , Розумна Обробка помилок 2 , і обслуговування Розумна Помилки 3 Нікласа Frykholm. Насправді, читайте всі статті цього блогу, поки ви в цьому. Не скажу, що я з усім згоден, але більшість це золото.
Не використовуйте винятки. Є безліч причин. Я перерахую основні з них.
Вони справді можуть бути повільнішими, хоча це зменшується на нових компіляторах. Деякі компілятори підтримують "нульові накладні винятки" для кодових шляхів, які насправді не викликають виключення (хоча це трохи брехня, оскільки все ще є додаткові дані, необхідні для обробки винятків, роздуття вашого розміру виконуваного файлу / dll). Кінцевий результат, однак, полягає в тому, що так, використання винятків відбувається повільніше, і в будь-яких критичних кодах до ефективності слід абсолютно уникати їх. Залежно від вашого компілятора, включення їх взагалі може додавати накладні витрати. Вони завжди завжди розширюють розмір коду, доволі значно у багатьох випадках, що може сильно вплинути на продуктивність сучасного обладнання.
Винятки роблять код набагато крихкішим. Існує сумнозвісна графіка (яку я, на жаль, зараз не можу знайти), яка в основному просто показує на графіку складність написання безпечного для винятку коду проти винятку-небезпечного коду, а перший - значно більший штрих. За винятком просто багато маленьких діточок, і існує безліч способів написання коду, який виглядає безпечним, але насправді це не так. Навіть увесь комітет C ++ 11 замислився на цьому і забув додати важливі допоміжні функції для правильного використання std :: unique_ptr, і навіть за допомогою цих допоміжних функцій потрібно більше вводити текст, щоб використовувати їх, ніж не, і більшість програмістів виграли ' навіть не розумію, що не так, якщо вони цього не роблять.
Більш конкретно для ігрової індустрії, деякі компілятори / програми виконання постачальників консолей прямо не підтримують винятки повністю або взагалі не підтримують їх. Якщо ваш код використовує винятки, можливо, вам все ж доведеться переписувати частини свого коду, щоб перенести його на нові платформи. (Не впевнений, що це змінилося за 7 років з моменту випуску зазначених консолей; ми просто не використовуємо винятки, вони навіть відключені в налаштуваннях компілятора, тому я не знаю, що хтось, з ким я спілкуюся, навіть нещодавно перевіряв.)
Загальна лінія мислення досить чітка: використовуйте винятки для виняткових обставин. Використовуйте їх, коли ваша програма потрапляє в "Я поняття не маю, що робити, можливо, сподіваюся, це зробить хтось інший, тому я кину виняток і побачу, що станеться". Використовуйте їх, коли жоден інший варіант не має сенсу. Використовуйте їх, коли вам не байдуже, якщо ви випадково просочилися небагато пам’яті або не вдалося очистити ресурс, оскільки ви заплутали використання належних розумних ручок. У всіх інших випадках не використовуйте їх.
Що стосується коду, як ваш приклад, у вас є кілька інших способів виправити проблему. Один з найбільш надійних - хоча і не обов'язково найбільш ідеальний у вашому простому прикладі - це схилятися до монадичних типів помилок. Тобто createText () може повернути власний тип обробки, а не ціле число. Цей тип ручки має аксесуари для оновлення або контролю тексту. Якщо ручка буде переведена в стан помилки (тому що createText () не вдалося), то подальший виклик на ручку просто виходить з ладу. Ви також можете запитати ручку, щоб побачити, чи вона помилилася, і якщо так, то яка остання помилка. Цей підхід має більше накладних витрат, ніж інші варіанти, але він досить солідний. Використовуйте його у тих випадках, коли вам потрібно виконати довгу низку операцій у певному контексті, коли будь-яка окрема операція може бути невдалою у виробництві, але коли ви не / не можете / виграли '
Альтернативою реалізації монадичної обробки помилок є, замість того, щоб використовувати власні об'єкти обробки, щоб методи на контекстному об'єкті витончено боролися з недійсними ідентифікаторами обробки. Наприклад, якщо createText () повертає -1, коли він не працює, то будь-які інші виклики до m_statistics, які беруть одну з цих ручок, повинні витончено закриватися, якщо -1 передано в.
Ви також можете поставити помилку друку всередині функції, яка насправді не працює. У вашому прикладі createText (), ймовірно, має більше інформації про те, що пішло не так, тож ви зможете скинути в журнал більш значущу помилку. Немало користі в цьому випадку для виштовхування помилок на обробку / друкування помилок. Зробіть це, коли абонентам потрібно налаштувати обробку (або використовувати ін'єкцію залежності). Зауважте, що наявність ігрової консолі, яка може з’являтись під час реєстрації помилки, є хорошою ідеєю і тут також допомагає.
Найкращий варіант (вже представлений у зв'язаній серії статей вище) для дзвінків, які ви не очікуєте збою в будь-якому розумному середовищі - наприклад, простий акт створення текстових крапок для системи статистики - просто мати функцію що не вдалося (createText у вашому прикладі) скасувати. Ви можете бути впевнені, що createText () не вийде з ладу у виробництві, якщо щось не виграє (наприклад, користувач видалив файли даних шрифтів або чомусь має лише 256 МБ пам'яті тощо). У багатьох із цих випадків навіть не дуже добре робити те, коли відбувається збій. Недостатньо помяті? Можливо, ви навіть не зможете зробити виділення, необхідне для створення приємної панелі GUI, щоб показати користувачеві помилку OOM. Відсутні шрифти? Утрудняє відображення помилок користувачеві. Що б не було,
Просто збій є цілком нормальним, доки ви (a) записуєте помилку у файл журналу та (b) робите це лише на помилках, які не викликаються звичайними діями користувача.
Я б не сказав те ж саме для багатьох серверних додатків, де доступність є критичною, а моніторинг сторожового контролю недостатній, але це зовсім інше, ніж розробка клієнтських ігор . Я також наполегливо уникатимуть використання C / C ++ там, оскільки засоби оброблення винятків інших мов, як правило, не кусаються, як C ++, оскільки вони керовані середовищем і не мають усіх проблем із безпекою для винятку, які мають C ++. Будь-які занепокоєння щодо продуктивності також зменшуються, оскільки сервери, як правило, зосереджуються більше на паралельності та пропускній спроможності, ніж на мінімальних гарантіях затримки, як ігрові клієнти. Навіть сервери ігрових дій для шутерів тощо можуть працювати досить добре, коли вони написані на C #, оскільки вони рідко підштовхують обладнання до своїх меж, як це роблять клієнти FPS.