Я думаю, @JackAidley вже сказав суть цього , але дозвольте сформулювати це так:
без винятків (наприклад, C)
У регулярному потоці коду у вас є:
if (condition) {
statement;
} else if (less_likely_condition) {
less_likely_statement;
} else {
least_likely_statement;
}
more_statements;
У випадку "рано помилка" ваш код раптом звучить:
/* demonstration example, do NOT code like this */
if (condition) {
statement;
} else {
error_handling;
return;
}
Якщо ви помітили цю модель - це returnв else(або навіть if) блоці, переробити його негайно , так що код в питанні зовсім НЕ має elseблоку:
/* only code like this at University, to please structured programming professors */
function foo {
if (condition) {
lots_of_statements;
}
return;
}
У реальному світі ...
/* code like this instead */
if (!condition) {
error_handling;
return;
}
lots_of_statements;
Це дозволяє уникнути занадто глибокого гніздування та виконує випадок «рано вирватися» (допомагає зберегти розум - і потік коду - чистим) і не порушує «поставити більш детальну річ у ifчастину», оскільки просто немає її elseчастини .
C та очищення
Ось натхненний відповіддю на аналогічне запитання (яке помилилось), ось як зробити очищення за допомогою C. Тут ви можете використовувати одну або дві точки виходу, ось одна для двох точок виходу:
struct foo *
alloc_and_init(size_t arg1, int arg2)
{
struct foo *res;
if (!(res = calloc(sizeof(struct foo), 1)))
return (NULL);
if (foo_init1(res, arg1))
goto err;
res.arg1_inited = true;
if (foo_init2(&(res->blah), arg2))
goto err;
foo_init_complete(res);
return (res);
err:
/* safe because we use calloc and false == 0 */
if (res.arg1_inited)
foo_dispose1(res);
free(res);
return (NULL);
}
Ви можете згорнути їх в одну точку виходу, якщо робити менше очищення:
char *
NULL_safe_strdup(const char *arg)
{
char *res = NULL;
if (arg == NULL)
goto out;
/* imagine more lines here */
res = strdup(arg);
out:
return (res);
}
Це використання gotoпрекрасно, якщо ви можете з цим впоратися; порада відмовитися від використання gotoспрямована на людей, які ще не можуть самостійно вирішити, чи це використання добре, прийнятно, погано, код спагетті чи щось інше.
Винятки
Вище сказано про мови без винятків, які я дуже віддаю перевагу (я можу використовувати явні помилки в роботі набагато краще і з набагато меншим подивом). Щоб цитувати іглі:
<igli> exceptions: a truly awful implementation of quite a nice idea.
<igli> just about the worst way you could do something like that, afaic.
<igli> it's like anti-design.
<mirabilos> that too… may I quote you on that?
<igli> sure, tho i doubt anyone will listen ;)
Але ось пропозиція, як ви робите це добре мовою з винятками, і коли ви хочете їх добре використовувати:
повернення помилок перед винятками
Можна замінити більшу частину ранніх returnс викиданням винятку. Однак ваш нормальний потік програми, тобто будь-який потік коду, в якому програма не зустрічається, ну, виняток… Умова помилки або щось таке, не повинно викликати жодних винятків.
Це означає що…
# this page is only available to logged-in users
if not isLoggedIn():
# this is Python 2.5 style; insert your favourite raise/throw here
raise "eh?"
... це добре, але ...
/* do not code like this! */
try {
openFile(xyz, "rw");
} catch (LockedException e) {
return "file is locked";
}
closeFile(xyz);
return "file is not locked";
… не. В основному виняток не є елементом керуючого потоку . Це також робить операції дивними на вас ("ті програмісти Java ™ завжди говорять нам, що ці винятки є нормальними") і можуть перешкоджати налагодженню (наприклад, скажіть IDE просто зламати будь-який виняток). Винятки часто вимагають, щоб середовище виконання часу розмотувало стек для створення слідів тощо. Напевно, існує більше причин проти цього.
Це зводиться до: мовою, яка підтримує винятки, використовувати все, що відповідає існуючій логіці та стилю, і відчуває себе природним. Якщо ви пишете щось з нуля, домовтеся про це рано. Якщо ви пишете бібліотеку з нуля, подумайте про своїх споживачів. (Ніколи не використовуйте ні abort()в бібліотеці…) Але що б ви не робили, не допускайте викидів, як правило, викидів, якщо після цього операція триває (більш-менш).
загальна рада wrt. Винятки
Спробуйте спочатку отримати все винятки в програмі, про які погодилася вся команда розробників. В основному, плануйте їх. Не використовуйте їх в достатку. Іноді, навіть у C ++, Java ™, Python, повернення помилок краще. Іноді це не так; використовувати їх з думкою.