> // тут v автоматично знищується
Коли вектор v знищується, він відповідає за знищення всіх об'єктів Widget, які в ньому містяться. Припустимо, що v містить 10 об'єктів Widget, і під час знищення першого з них возбужается виняток. Решта дев'ять об'єктів Widget також повинні бути знищені (інакше ресурси, виділені для них, будуть втрачені), тому необхідно викликати і їх деструктори. Але уявімо, що в цей час деструктор другого об'єкта Widget також порушить виняток. Тоді виникне відразу два одночасно активних виключення, а це занадто багато для C ++. Залежно від конкретних умов виконання програми або буде перервано, або її поведінку виявиться невизначеним. У цьому прикладі як раз має місце другий випадок. І так буде відбуватися при використанні будь-якого бібліотечного контейнера (наприклад, list, set), будь-якого контейнера TR1 (див. Правило 54) і навіть масиву. І причина цієї проблеми не в контейнерах або масивах. Передчасне завершення програми або невизначений поведінка тут є результатом того, що деструктори збуджують виключення. C ++ не любить деструкторов, що збуджують винятку!
Це досить просто зрозуміти. Але що ви повинні робити, якщо у вашому деструкції необхідно виконати операцію, яка може породити виняток? Наприклад, припустимо, що ми маємо справу з класом, що описує підключення до бази даних:
static DBConnection create (); // функція повертає об'єкт
// DBConnection; параметри для
void close (); // закрити з'єднання; при невдачі
Щоб переконатися у тому, що клієнт не забуде викликати close для об'єктів DBConnection, резонно створити клас для управління ресурсами DBConnection, який викликає close в своєму деструкції. Класи, що управляють ресурсами, ми детально розглянемо в розділі 3, а тут досить прикинути, як повинен виглядати деструктор такого класу:
class DBConn / Класс для управления объектами
DBConn () // забезпечити, щоб з'єднання з базою