Радий, що ви опублікували це як питання. :)
Я намагався сказати, що деструктори і finally
концептуально різні:
- Деструктори для випуску ресурсів ( даних )
finally
призначений для повернення абоненту ( контроль )
Розглянемо, скажімо, цей гіпотетичний псевдокод:
try {
bar();
} finally {
logfile.print("bar has exited...");
}
finally
тут вирішується повністю проблема управління, а не проблема управління ресурсами.
Не було б сенсу робити це в деструкторі з різних причин:
- Ні річ не бути «придбала» або «створив»
- Якщо не надрукувати файл журналу, це не призведе до витоку ресурсів, пошкодження даних тощо (якщо припустити, що файл журналу тут не повертається в програму в іншому місці)
- Це правомірно
logfile.print
відмовити, тоді як руйнування (концептуально) не може зазнати збою
Ось ще один приклад, цього разу, як у Javascript:
var mo_document = document, mo;
function observe(mutations) {
mo.disconnect(); // stop observing changes to prevent re-entrance
try {
/* modify stuff */
} finally {
mo.observe(mo_document); // continue observing (conceptually, this can fail)
}
}
mo = new MutationObserver(observe);
return observe();
У наведеному вище прикладі, знову ж таки, немає ресурсів для звільнення.
Насправді, finally
блок отримання внутрішніх ресурсів для досягнення своєї мети, яка потенційно може потерпіти невдачу. Отже, не має сенсу використовувати деструктор (якщо у Javascript був такий).
З іншого боку, у цьому прикладі:
b = get_data();
try {
a.write(b);
} finally {
free(b);
}
finally
знищує ресурс, b
. Це проблема даних. Проблема полягає не в чистому поверненні контролю абоненту, а в уникненні витоків ресурсів.
Відмова не є варіантом, і не повинен (концептуально) ніколи виникати.
Кожен реліз b
обов'язково поєднується з придбанням, і є сенс використовувати RAII.
Іншими словами, тільки тому, що ви можете використовувати або для імітації, або це не означає, що обидві є однією і тією ж проблемою, або що обидва є відповідними рішеннями для обох проблем.