Отже, моє запитання таке: якщо викидання з деструктора призводить до невизначеної поведінки, як ви обробляєте помилки, які виникають під час деструктора?
Основна проблема полягає в цьому: ти не можеш не зірватися . Що означає, зрештою, зазнати невдачі? Якщо здійснення транзакції з базою даних не вдається, а вона не дає змоги (не вдалося відкатати), що відбувається з цілісністю наших даних?
Оскільки деструктори викликаються як для нормальних, так і для виняткових (невдалих) шляхів, вони самі не можуть вийти з ладу, інакше ми "не вдається провалитися".
Це концептуально складна проблема, але часто рішення полягає в тому, щоб просто знайти спосіб переконатися, що невдача не може провалитися. Наприклад, база даних може записувати зміни перед введенням у зовнішню структуру даних або файл. Якщо транзакція не вдається, то структуру файлу / даних можна викинути. Тоді потрібно лише переконатися, що внесення змін із зовнішньої структури / файлу атомної транзакції, яка не може завершитись.
Прагматичне рішення, можливо, просто переконається, що шанси на невдачу є астрономічно малоймовірними, оскільки робити неможливим, щоб речі не змогли зазнати невдачі, в деяких випадках може бути майже неможливим.
Найбільш правильне рішення для мене - написати свою логіку не очищення таким чином, щоб логіка очищення не могла вийти з ладу. Наприклад, якщо ви спокусилися створити нову структуру даних, щоб очистити існуючу структуру даних, то, можливо, ви можете спробувати створити цю допоміжну структуру заздалегідь, щоб нам більше не довелося створювати її всередині деструктора.
Це все набагато простіше сказати, ніж це зробити, правда, але це єдиний дійсно правильний шлях, який я можу зробити. Іноді я думаю, що має бути можливість писати окремі логіки деструктора для нормальних шляхів виконання подалі від виняткових, оскільки іноді деструктори відчувають себе трохи схожими на їх подвійні обов'язки, намагаючись впоратися з обома (наприклад, охоронці сфери, які вимагають явного звільнення вони цього не вимагатимуть, якщо вони зможуть відрізняти виняткові шляхи руйнування від невиключних).
Все ж остаточна проблема полягає в тому, що ми не можемо не зазнати невдачі, і важко вирішити проблему концептуального дизайну у всіх випадках. Це стає легше, якщо ви не занадто загорнуті в складні структури управління з тоннами маленьких предметів, що взаємодіють між собою, а замість цього моделюйте свої конструкції трохи об'ємніше (наприклад: система частинок із руйнувачем, щоб знищити всю частинку система, а не окремий нетривіальний деструктор на частинку). Коли ви розробляєте свої конструкції на такому грубішому рівні, у вас є менше нетривіальних деструкторів, з якими можна боротися, а також ви можете часто дозволити собі будь-яку необхідну пам'ять / обробку, щоб переконатися, що ваші деструктори не зможуть вийти з ладу.
І це, звичайно, одне з найпростіших рішень - використовувати деструктори рідше. У наведеному вище прикладі, можливо, при знищенні / видаленні частинки слід зробити деякі речі, які можуть збитись з будь-якої причини. У такому випадку, замість того, щоб викликати таку логіку через дторг частинки, який міг би бути виконаний у винятковий шлях, замість цього ви можете зробити все це системою частинок, коли вона видаляє частинку. Видалення частинки завжди може бути здійснено під час не виключного шляху. Якщо система зруйнована, можливо, вона може просто очистити всі частинки і не заважати тій логіці вилучення окремих частинок, яка може вийти з ладу, тоді як логіка, яка може вийти з ладу, виконується лише під час звичайного виконання системи частинок, коли вона видаляє одну або кілька частинок.
Часто існують такі рішення, які з'являються, якщо ви уникаєте поводження з великою кількістю підліткових об'єктів з нетривіальними руйнівниками. Там, де можна заплутатися в безладі, де здається, що виняток винятком майже неможливий - це безпека, коли ти заблукаєш у безлічі підліткових предметів, у яких усі нетривіальні двигуни.
Це дуже допоможе, якщо nothrow / noexcept насправді переведений на помилку компілятора, якщо все, що його визначає (включаючи віртуальні функції, які повинні успадкувати специфікацію noexcept його базового класу), спробує викликати все, що може кинути. Таким чином, ми зможемо зловити весь цей матеріал під час компіляції, якщо ми насправді запишемо деструктор ненавмисно, який може кинути.